<?php

/**
 * FbaOutboundApi
 * PHP version 8.3.
 *
 * @category Class
 *
 * @author   OpenAPI Generator team
 *
 * @see     https://openapi-generator.tech
 */

/**
 * Selling Partner APIs for Fulfillment Outbound.
 *
 * The Selling Partner API for Fulfillment Outbound lets you create applications that help a seller fulfill Multi-Channel Fulfillment orders using their inventory in Amazon's fulfillment network. You can get information on both potential and existing fulfillment orders.
 *
 * The version of the OpenAPI document: 2020-07-01
 * Generated by: https://openapi-generator.tech
 * Generator version: 7.9.0
 */

/**
 * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
 * https://openapi-generator.tech
 * Do not edit the class manually.
 */

namespace SpApi\Api\fulfillment\outbound\v2020_07_01;

use GuzzleHttp\Client;
use GuzzleHttp\ClientInterface;
use GuzzleHttp\Exception\ConnectException;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Promise\PromiseInterface;
use GuzzleHttp\Psr7\MultipartStream;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\RequestOptions;
use SpApi\ApiException;
use SpApi\AuthAndAuth\RestrictedDataTokenSigner;
use SpApi\Configuration;
use SpApi\HeaderSelector;
use SpApi\Model\fulfillment\outbound\v2020_07_01\CancelFulfillmentOrderResponse;
use SpApi\Model\fulfillment\outbound\v2020_07_01\CreateFulfillmentOrderRequest;
use SpApi\Model\fulfillment\outbound\v2020_07_01\CreateFulfillmentOrderResponse;
use SpApi\Model\fulfillment\outbound\v2020_07_01\CreateFulfillmentReturnRequest;
use SpApi\Model\fulfillment\outbound\v2020_07_01\CreateFulfillmentReturnResponse;
use SpApi\Model\fulfillment\outbound\v2020_07_01\GetDeliveryOffersRequest;
use SpApi\Model\fulfillment\outbound\v2020_07_01\GetDeliveryOffersResponse;
use SpApi\Model\fulfillment\outbound\v2020_07_01\GetFeatureInventoryResponse;
use SpApi\Model\fulfillment\outbound\v2020_07_01\GetFeatureSkuResponse;
use SpApi\Model\fulfillment\outbound\v2020_07_01\GetFeaturesResponse;
use SpApi\Model\fulfillment\outbound\v2020_07_01\GetFulfillmentOrderResponse;
use SpApi\Model\fulfillment\outbound\v2020_07_01\GetFulfillmentPreviewRequest;
use SpApi\Model\fulfillment\outbound\v2020_07_01\GetFulfillmentPreviewResponse;
use SpApi\Model\fulfillment\outbound\v2020_07_01\GetPackageTrackingDetailsResponse;
use SpApi\Model\fulfillment\outbound\v2020_07_01\ListAllFulfillmentOrdersResponse;
use SpApi\Model\fulfillment\outbound\v2020_07_01\ListReturnReasonCodesResponse;
use SpApi\Model\fulfillment\outbound\v2020_07_01\SubmitFulfillmentOrderStatusUpdateRequest;
use SpApi\Model\fulfillment\outbound\v2020_07_01\SubmitFulfillmentOrderStatusUpdateResponse;
use SpApi\Model\fulfillment\outbound\v2020_07_01\UpdateFulfillmentOrderRequest;
use SpApi\Model\fulfillment\outbound\v2020_07_01\UpdateFulfillmentOrderResponse;
use SpApi\ObjectSerializer;
use Symfony\Component\RateLimiter\LimiterInterface;
use Symfony\Component\RateLimiter\RateLimiterFactory;
use Symfony\Component\RateLimiter\Storage\InMemoryStorage;

/**
 * FbaOutboundApi Class Doc Comment.
 *
 * @category Class
 *
 * @author   OpenAPI Generator team
 *
 * @see     https://openapi-generator.tech
 */
class FbaOutboundApi
{
    public ?LimiterInterface $cancelFulfillmentOrderRateLimiter;
    public ?LimiterInterface $createFulfillmentOrderRateLimiter;
    public ?LimiterInterface $createFulfillmentReturnRateLimiter;
    public ?LimiterInterface $deliveryOffersRateLimiter;
    public ?LimiterInterface $getFeatureInventoryRateLimiter;
    public ?LimiterInterface $getFeatureSKURateLimiter;
    public ?LimiterInterface $getFeaturesRateLimiter;
    public ?LimiterInterface $getFulfillmentOrderRateLimiter;
    public ?LimiterInterface $getFulfillmentPreviewRateLimiter;
    public ?LimiterInterface $getPackageTrackingDetailsRateLimiter;
    public ?LimiterInterface $listAllFulfillmentOrdersRateLimiter;
    public ?LimiterInterface $listReturnReasonCodesRateLimiter;
    public ?LimiterInterface $submitFulfillmentOrderStatusUpdateRateLimiter;
    public ?LimiterInterface $updateFulfillmentOrderRateLimiter;
    protected ClientInterface $client;

    protected Configuration $config;

    protected HeaderSelector $headerSelector;

    /**
     * @var int Host index
     */
    protected int $hostIndex;

    private bool $rateLimiterEnabled;
    private InMemoryStorage $rateLimitStorage;

    /**
     * @param int $hostIndex (Optional) host index to select the list of hosts if defined in the OpenAPI spec
     */
    public function __construct(
        Configuration $config,
        ?ClientInterface $client = null,
        ?bool $rateLimiterEnabled = true,
        ?HeaderSelector $selector = null,
        int $hostIndex = 0
    ) {
        $this->config = $config;
        $this->rateLimiterEnabled = $rateLimiterEnabled;

        if ($rateLimiterEnabled) {
            $this->rateLimitStorage = new InMemoryStorage();

            $factory = new RateLimiterFactory(Configuration::getRateLimitOptions('FbaOutboundApi-cancelFulfillmentOrder'), $this->rateLimitStorage);
            $this->cancelFulfillmentOrderRateLimiter = $factory->create('FbaOutboundApi-cancelFulfillmentOrder');
            $factory = new RateLimiterFactory(Configuration::getRateLimitOptions('FbaOutboundApi-createFulfillmentOrder'), $this->rateLimitStorage);
            $this->createFulfillmentOrderRateLimiter = $factory->create('FbaOutboundApi-createFulfillmentOrder');
            $factory = new RateLimiterFactory(Configuration::getRateLimitOptions('FbaOutboundApi-createFulfillmentReturn'), $this->rateLimitStorage);
            $this->createFulfillmentReturnRateLimiter = $factory->create('FbaOutboundApi-createFulfillmentReturn');
            $factory = new RateLimiterFactory(Configuration::getRateLimitOptions('FbaOutboundApi-deliveryOffers'), $this->rateLimitStorage);
            $this->deliveryOffersRateLimiter = $factory->create('FbaOutboundApi-deliveryOffers');
            $factory = new RateLimiterFactory(Configuration::getRateLimitOptions('FbaOutboundApi-getFeatureInventory'), $this->rateLimitStorage);
            $this->getFeatureInventoryRateLimiter = $factory->create('FbaOutboundApi-getFeatureInventory');
            $factory = new RateLimiterFactory(Configuration::getRateLimitOptions('FbaOutboundApi-getFeatureSKU'), $this->rateLimitStorage);
            $this->getFeatureSKURateLimiter = $factory->create('FbaOutboundApi-getFeatureSKU');
            $factory = new RateLimiterFactory(Configuration::getRateLimitOptions('FbaOutboundApi-getFeatures'), $this->rateLimitStorage);
            $this->getFeaturesRateLimiter = $factory->create('FbaOutboundApi-getFeatures');
            $factory = new RateLimiterFactory(Configuration::getRateLimitOptions('FbaOutboundApi-getFulfillmentOrder'), $this->rateLimitStorage);
            $this->getFulfillmentOrderRateLimiter = $factory->create('FbaOutboundApi-getFulfillmentOrder');
            $factory = new RateLimiterFactory(Configuration::getRateLimitOptions('FbaOutboundApi-getFulfillmentPreview'), $this->rateLimitStorage);
            $this->getFulfillmentPreviewRateLimiter = $factory->create('FbaOutboundApi-getFulfillmentPreview');
            $factory = new RateLimiterFactory(Configuration::getRateLimitOptions('FbaOutboundApi-getPackageTrackingDetails'), $this->rateLimitStorage);
            $this->getPackageTrackingDetailsRateLimiter = $factory->create('FbaOutboundApi-getPackageTrackingDetails');
            $factory = new RateLimiterFactory(Configuration::getRateLimitOptions('FbaOutboundApi-listAllFulfillmentOrders'), $this->rateLimitStorage);
            $this->listAllFulfillmentOrdersRateLimiter = $factory->create('FbaOutboundApi-listAllFulfillmentOrders');
            $factory = new RateLimiterFactory(Configuration::getRateLimitOptions('FbaOutboundApi-listReturnReasonCodes'), $this->rateLimitStorage);
            $this->listReturnReasonCodesRateLimiter = $factory->create('FbaOutboundApi-listReturnReasonCodes');
            $factory = new RateLimiterFactory(Configuration::getRateLimitOptions('FbaOutboundApi-submitFulfillmentOrderStatusUpdate'), $this->rateLimitStorage);
            $this->submitFulfillmentOrderStatusUpdateRateLimiter = $factory->create('FbaOutboundApi-submitFulfillmentOrderStatusUpdate');
            $factory = new RateLimiterFactory(Configuration::getRateLimitOptions('FbaOutboundApi-updateFulfillmentOrder'), $this->rateLimitStorage);
            $this->updateFulfillmentOrderRateLimiter = $factory->create('FbaOutboundApi-updateFulfillmentOrder');
        }

        $this->client = $client ?: new Client();
        $this->headerSelector = $selector ?: new HeaderSelector();
        $this->hostIndex = $hostIndex;
    }

    /**
     * Set the host index.
     *
     * @param int $hostIndex Host index (required)
     */
    public function setHostIndex(int $hostIndex): void
    {
        $this->hostIndex = $hostIndex;
    }

    /**
     * Get the host index.
     *
     * @return int Host index
     */
    public function getHostIndex(): int
    {
        return $this->hostIndex;
    }

    public function getConfig(): Configuration
    {
        return $this->config;
    }

    /**
     * Operation cancelFulfillmentOrder.
     *
     * @param string      $seller_fulfillment_order_id
     *                                                 The identifier assigned to the item by the seller when the fulfillment order was created. (required)
     * @param null|string $restrictedDataToken         Restricted Data Token (RDT) for accessing restricted resources (optional, required for operations that return PII)
     *
     * @throws ApiException              on non-2xx response
     * @throws \InvalidArgumentException
     */
    public function cancelFulfillmentOrder(
        string $seller_fulfillment_order_id,
        ?string $restrictedDataToken = null
    ): CancelFulfillmentOrderResponse {
        list($response) = $this->cancelFulfillmentOrderWithHttpInfo($seller_fulfillment_order_id, $restrictedDataToken);

        return $response;
    }

    /**
     * Operation cancelFulfillmentOrderWithHttpInfo.
     *
     * @param string      $seller_fulfillment_order_id
     *                                                 The identifier assigned to the item by the seller when the fulfillment order was created. (required)
     * @param null|string $restrictedDataToken         Restricted Data Token (RDT) for accessing restricted resources (optional, required for operations that return PII)
     *
     * @return array of \SpApi\Model\fulfillment\outbound\v2020_07_01\CancelFulfillmentOrderResponse, HTTP status code, HTTP response headers (array of strings)
     *
     * @throws ApiException              on non-2xx response
     * @throws \InvalidArgumentException
     */
    public function cancelFulfillmentOrderWithHttpInfo(
        string $seller_fulfillment_order_id,
        ?string $restrictedDataToken = null
    ): array {
        $request = $this->cancelFulfillmentOrderRequest($seller_fulfillment_order_id);
        if (null !== $restrictedDataToken) {
            $request = RestrictedDataTokenSigner::sign($request, $restrictedDataToken, 'FbaOutboundApi-cancelFulfillmentOrder');
        } else {
            $request = $this->config->sign($request);
        }

        try {
            $options = $this->createHttpClientOption();

            try {
                if ($this->rateLimiterEnabled) {
                    $this->cancelFulfillmentOrderRateLimiter->consume()->ensureAccepted();
                }
                $response = $this->client->send($request, $options);
            } catch (RequestException $e) {
                throw new ApiException(
                    "[{$e->getCode()}] {$e->getResponse()->getBody()}",
                    (int) $e->getCode(),
                    $e->getResponse() ? $e->getResponse()->getHeaders() : null,
                    $e->getResponse() ? (string) $e->getResponse()->getBody() : null
                );
            } catch (ConnectException $e) {
                throw new ApiException(
                    "[{$e->getCode()}] {$e->getMessage()}",
                    (int) $e->getCode(),
                    null,
                    null
                );
            }

            $statusCode = $response->getStatusCode();

            if ($statusCode < 200 || $statusCode > 299) {
                throw new ApiException(
                    sprintf(
                        '[%d] Error connecting to the API (%s)',
                        $statusCode,
                        (string) $request->getUri()
                    ),
                    $statusCode,
                    $response->getHeaders(),
                    (string) $response->getBody()
                );
            }
            if ('\SpApi\Model\fulfillment\outbound\v2020_07_01\CancelFulfillmentOrderResponse' === '\SplFileObject') {
                $content = $response->getBody(); // stream goes to serializer
            } else {
                $content = (string) $response->getBody();
                if ('\SpApi\Model\fulfillment\outbound\v2020_07_01\CancelFulfillmentOrderResponse' !== 'string') {
                    $content = json_decode($content);
                }
            }

            return [
                ObjectSerializer::deserialize($content, '\SpApi\Model\fulfillment\outbound\v2020_07_01\CancelFulfillmentOrderResponse', []),
                $response->getStatusCode(),
                $response->getHeaders(),
            ];
        } catch (ApiException $e) {
            $data = ObjectSerializer::deserialize(
                $e->getResponseBody(),
                '\SpApi\Model\fulfillment\outbound\v2020_07_01\CancelFulfillmentOrderResponse',
                $e->getResponseHeaders()
            );
            $e->setResponseObject($data);

            throw $e;
        }
    }

    /**
     * Operation cancelFulfillmentOrderAsync.
     *
     * @param string $seller_fulfillment_order_id
     *                                            The identifier assigned to the item by the seller when the fulfillment order was created. (required)
     *
     * @throws \InvalidArgumentException
     */
    public function cancelFulfillmentOrderAsync(
        string $seller_fulfillment_order_id
    ): PromiseInterface {
        return $this->cancelFulfillmentOrderAsyncWithHttpInfo($seller_fulfillment_order_id)
            ->then(
                function ($response) {
                    return $response[0];
                }
            )
        ;
    }

    /**
     * Operation cancelFulfillmentOrderAsyncWithHttpInfo.
     *
     * @param string $seller_fulfillment_order_id
     *                                            The identifier assigned to the item by the seller when the fulfillment order was created. (required)
     *
     * @throws \InvalidArgumentException
     */
    public function cancelFulfillmentOrderAsyncWithHttpInfo(
        string $seller_fulfillment_order_id,
        ?string $restrictedDataToken = null
    ): PromiseInterface {
        $returnType = '\SpApi\Model\fulfillment\outbound\v2020_07_01\CancelFulfillmentOrderResponse';
        $request = $this->cancelFulfillmentOrderRequest($seller_fulfillment_order_id);
        if (null !== $restrictedDataToken) {
            $request = RestrictedDataTokenSigner::sign($request, $restrictedDataToken, 'FbaOutboundApi-cancelFulfillmentOrder');
        } else {
            $request = $this->config->sign($request);
        }
        if ($this->rateLimiterEnabled) {
            $this->cancelFulfillmentOrderRateLimiter->consume()->ensureAccepted();
        }

        return $this->client
            ->sendAsync($request, $this->createHttpClientOption())
            ->then(
                function ($response) use ($returnType) {
                    if ('\SplFileObject' === $returnType) {
                        $content = $response->getBody(); // stream goes to serializer
                    } else {
                        $content = (string) $response->getBody();
                        if ('string' !== $returnType) {
                            $content = json_decode($content);
                        }
                    }

                    return [
                        ObjectSerializer::deserialize($content, $returnType, []),
                        $response->getStatusCode(),
                        $response->getHeaders(),
                    ];
                },
                function ($exception) {
                    $response = $exception->getResponse();
                    $statusCode = $response->getStatusCode();

                    throw new ApiException(
                        sprintf(
                            '[%d] Error connecting to the API (%s)',
                            $statusCode,
                            $exception->getRequest()->getUri()
                        ),
                        $statusCode,
                        $response->getHeaders(),
                        (string) $response->getBody()
                    );
                }
            )
        ;
    }

    /**
     * Create request for operation 'cancelFulfillmentOrder'.
     *
     * @param string $seller_fulfillment_order_id
     *                                            The identifier assigned to the item by the seller when the fulfillment order was created. (required)
     *
     * @throws \InvalidArgumentException
     */
    public function cancelFulfillmentOrderRequest(
        string $seller_fulfillment_order_id
    ): Request {
        // verify the required parameter 'seller_fulfillment_order_id' is set
        if (null === $seller_fulfillment_order_id || (is_array($seller_fulfillment_order_id) && 0 === count($seller_fulfillment_order_id))) {
            throw new \InvalidArgumentException(
                'Missing the required parameter $seller_fulfillment_order_id when calling cancelFulfillmentOrder'
            );
        }
        if (strlen($seller_fulfillment_order_id) > 40) {
            throw new \InvalidArgumentException('invalid length for "$seller_fulfillment_order_id" when calling FbaOutboundApi.cancelFulfillmentOrder, must be smaller than or equal to 40.');
        }

        $resourcePath = '/fba/outbound/2020-07-01/fulfillmentOrders/{sellerFulfillmentOrderId}/cancel';
        $formParams = [];
        $queryParams = [];
        $headerParams = [];
        $httpBody = '';
        $multipart = false;

        // path params
        if (null !== $seller_fulfillment_order_id) {
            $resourcePath = str_replace(
                '{sellerFulfillmentOrderId}',
                ObjectSerializer::toPathValue($seller_fulfillment_order_id),
                $resourcePath
            );
        }

        $headers = $this->headerSelector->selectHeaders(
            ['application/json'],
            '',
            $multipart
        );

        // for model (json/xml)
        if (count($formParams) > 0) {
            if ($multipart) {
                $multipartContents = [];
                foreach ($formParams as $formParamName => $formParamValue) {
                    $formParamValueItems = is_array($formParamValue) ? $formParamValue : [$formParamValue];
                    foreach ($formParamValueItems as $formParamValueItem) {
                        $multipartContents[] = [
                            'name' => $formParamName,
                            'contents' => $formParamValueItem,
                        ];
                    }
                }
                // for HTTP post (form)
                $httpBody = new MultipartStream($multipartContents);
            } elseif ('application/json' === $headers['Content-Type']) {
                $httpBody = \GuzzleHttp\json_encode($formParams);
            } else {
                // for HTTP post (form)
                $httpBody = ObjectSerializer::buildQuery($formParams, $this->config);
            }
        }

        $defaultHeaders = [];
        if ($this->config->getUserAgent()) {
            $defaultHeaders['User-Agent'] = $this->config->getUserAgent();
        }

        $headers = array_merge(
            $defaultHeaders,
            $headerParams,
            $headers
        );

        $query = ObjectSerializer::buildQuery($queryParams, $this->config);

        return new Request(
            'PUT',
            $this->config->getHost().$resourcePath.($query ? "?{$query}" : ''),
            $headers,
            $httpBody
        );
    }

    /**
     * Operation createFulfillmentOrder.
     *
     * @param CreateFulfillmentOrderRequest $body
     *                                                           CreateFulfillmentOrderRequest parameter (required)
     * @param null|string                   $restrictedDataToken Restricted Data Token (RDT) for accessing restricted resources (optional, required for operations that return PII)
     *
     * @throws ApiException              on non-2xx response
     * @throws \InvalidArgumentException
     */
    public function createFulfillmentOrder(
        CreateFulfillmentOrderRequest $body,
        ?string $restrictedDataToken = null
    ): CreateFulfillmentOrderResponse {
        list($response) = $this->createFulfillmentOrderWithHttpInfo($body, $restrictedDataToken);

        return $response;
    }

    /**
     * Operation createFulfillmentOrderWithHttpInfo.
     *
     * @param CreateFulfillmentOrderRequest $body
     *                                                           CreateFulfillmentOrderRequest parameter (required)
     * @param null|string                   $restrictedDataToken Restricted Data Token (RDT) for accessing restricted resources (optional, required for operations that return PII)
     *
     * @return array of \SpApi\Model\fulfillment\outbound\v2020_07_01\CreateFulfillmentOrderResponse, HTTP status code, HTTP response headers (array of strings)
     *
     * @throws ApiException              on non-2xx response
     * @throws \InvalidArgumentException
     */
    public function createFulfillmentOrderWithHttpInfo(
        CreateFulfillmentOrderRequest $body,
        ?string $restrictedDataToken = null
    ): array {
        $request = $this->createFulfillmentOrderRequest($body);
        if (null !== $restrictedDataToken) {
            $request = RestrictedDataTokenSigner::sign($request, $restrictedDataToken, 'FbaOutboundApi-createFulfillmentOrder');
        } else {
            $request = $this->config->sign($request);
        }

        try {
            $options = $this->createHttpClientOption();

            try {
                if ($this->rateLimiterEnabled) {
                    $this->createFulfillmentOrderRateLimiter->consume()->ensureAccepted();
                }
                $response = $this->client->send($request, $options);
            } catch (RequestException $e) {
                throw new ApiException(
                    "[{$e->getCode()}] {$e->getResponse()->getBody()}",
                    (int) $e->getCode(),
                    $e->getResponse() ? $e->getResponse()->getHeaders() : null,
                    $e->getResponse() ? (string) $e->getResponse()->getBody() : null
                );
            } catch (ConnectException $e) {
                throw new ApiException(
                    "[{$e->getCode()}] {$e->getMessage()}",
                    (int) $e->getCode(),
                    null,
                    null
                );
            }

            $statusCode = $response->getStatusCode();

            if ($statusCode < 200 || $statusCode > 299) {
                throw new ApiException(
                    sprintf(
                        '[%d] Error connecting to the API (%s)',
                        $statusCode,
                        (string) $request->getUri()
                    ),
                    $statusCode,
                    $response->getHeaders(),
                    (string) $response->getBody()
                );
            }
            if ('\SpApi\Model\fulfillment\outbound\v2020_07_01\CreateFulfillmentOrderResponse' === '\SplFileObject') {
                $content = $response->getBody(); // stream goes to serializer
            } else {
                $content = (string) $response->getBody();
                if ('\SpApi\Model\fulfillment\outbound\v2020_07_01\CreateFulfillmentOrderResponse' !== 'string') {
                    $content = json_decode($content);
                }
            }

            return [
                ObjectSerializer::deserialize($content, '\SpApi\Model\fulfillment\outbound\v2020_07_01\CreateFulfillmentOrderResponse', []),
                $response->getStatusCode(),
                $response->getHeaders(),
            ];
        } catch (ApiException $e) {
            $data = ObjectSerializer::deserialize(
                $e->getResponseBody(),
                '\SpApi\Model\fulfillment\outbound\v2020_07_01\CreateFulfillmentOrderResponse',
                $e->getResponseHeaders()
            );
            $e->setResponseObject($data);

            throw $e;
        }
    }

    /**
     * Operation createFulfillmentOrderAsync.
     *
     * @param CreateFulfillmentOrderRequest $body
     *                                            CreateFulfillmentOrderRequest parameter (required)
     *
     * @throws \InvalidArgumentException
     */
    public function createFulfillmentOrderAsync(
        CreateFulfillmentOrderRequest $body
    ): PromiseInterface {
        return $this->createFulfillmentOrderAsyncWithHttpInfo($body)
            ->then(
                function ($response) {
                    return $response[0];
                }
            )
        ;
    }

    /**
     * Operation createFulfillmentOrderAsyncWithHttpInfo.
     *
     * @param CreateFulfillmentOrderRequest $body
     *                                            CreateFulfillmentOrderRequest parameter (required)
     *
     * @throws \InvalidArgumentException
     */
    public function createFulfillmentOrderAsyncWithHttpInfo(
        CreateFulfillmentOrderRequest $body,
        ?string $restrictedDataToken = null
    ): PromiseInterface {
        $returnType = '\SpApi\Model\fulfillment\outbound\v2020_07_01\CreateFulfillmentOrderResponse';
        $request = $this->createFulfillmentOrderRequest($body);
        if (null !== $restrictedDataToken) {
            $request = RestrictedDataTokenSigner::sign($request, $restrictedDataToken, 'FbaOutboundApi-createFulfillmentOrder');
        } else {
            $request = $this->config->sign($request);
        }
        if ($this->rateLimiterEnabled) {
            $this->createFulfillmentOrderRateLimiter->consume()->ensureAccepted();
        }

        return $this->client
            ->sendAsync($request, $this->createHttpClientOption())
            ->then(
                function ($response) use ($returnType) {
                    if ('\SplFileObject' === $returnType) {
                        $content = $response->getBody(); // stream goes to serializer
                    } else {
                        $content = (string) $response->getBody();
                        if ('string' !== $returnType) {
                            $content = json_decode($content);
                        }
                    }

                    return [
                        ObjectSerializer::deserialize($content, $returnType, []),
                        $response->getStatusCode(),
                        $response->getHeaders(),
                    ];
                },
                function ($exception) {
                    $response = $exception->getResponse();
                    $statusCode = $response->getStatusCode();

                    throw new ApiException(
                        sprintf(
                            '[%d] Error connecting to the API (%s)',
                            $statusCode,
                            $exception->getRequest()->getUri()
                        ),
                        $statusCode,
                        $response->getHeaders(),
                        (string) $response->getBody()
                    );
                }
            )
        ;
    }

    /**
     * Create request for operation 'createFulfillmentOrder'.
     *
     * @param CreateFulfillmentOrderRequest $body
     *                                            CreateFulfillmentOrderRequest parameter (required)
     *
     * @throws \InvalidArgumentException
     */
    public function createFulfillmentOrderRequest(
        CreateFulfillmentOrderRequest $body
    ): Request {
        // verify the required parameter 'body' is set
        if (null === $body || (is_array($body) && 0 === count($body))) {
            throw new \InvalidArgumentException(
                'Missing the required parameter $body when calling createFulfillmentOrder'
            );
        }

        $resourcePath = '/fba/outbound/2020-07-01/fulfillmentOrders';
        $formParams = [];
        $queryParams = [];
        $headerParams = [];
        $httpBody = '';
        $multipart = false;

        $headers = $this->headerSelector->selectHeaders(
            ['application/json'],
            'application/json',
            $multipart
        );

        // for model (json/xml)
        if (isset($body)) {
            if ('application/json' === $headers['Content-Type']) {
                $httpBody = \GuzzleHttp\json_encode(ObjectSerializer::sanitizeForSerialization($body));
            } else {
                $httpBody = $body;
            }
        } elseif (count($formParams) > 0) {
            if ($multipart) {
                $multipartContents = [];
                foreach ($formParams as $formParamName => $formParamValue) {
                    $formParamValueItems = is_array($formParamValue) ? $formParamValue : [$formParamValue];
                    foreach ($formParamValueItems as $formParamValueItem) {
                        $multipartContents[] = [
                            'name' => $formParamName,
                            'contents' => $formParamValueItem,
                        ];
                    }
                }
                // for HTTP post (form)
                $httpBody = new MultipartStream($multipartContents);
            } elseif ('application/json' === $headers['Content-Type']) {
                $httpBody = \GuzzleHttp\json_encode($formParams);
            } else {
                // for HTTP post (form)
                $httpBody = ObjectSerializer::buildQuery($formParams, $this->config);
            }
        }

        $defaultHeaders = [];
        if ($this->config->getUserAgent()) {
            $defaultHeaders['User-Agent'] = $this->config->getUserAgent();
        }

        $headers = array_merge(
            $defaultHeaders,
            $headerParams,
            $headers
        );

        $query = ObjectSerializer::buildQuery($queryParams, $this->config);

        return new Request(
            'POST',
            $this->config->getHost().$resourcePath.($query ? "?{$query}" : ''),
            $headers,
            $httpBody
        );
    }

    /**
     * Operation createFulfillmentReturn.
     *
     * @param string                         $seller_fulfillment_order_id
     *                                                                    An identifier assigned by the seller to the fulfillment order at the time it was created. The seller uses their own records to find the correct &#x60;SellerFulfillmentOrderId&#x60; value based on the buyer&#39;s request to return items. (required)
     * @param CreateFulfillmentReturnRequest $body
     *                                                                    CreateFulfillmentReturnRequest parameter (required)
     * @param null|string                    $restrictedDataToken         Restricted Data Token (RDT) for accessing restricted resources (optional, required for operations that return PII)
     *
     * @throws ApiException              on non-2xx response
     * @throws \InvalidArgumentException
     */
    public function createFulfillmentReturn(
        string $seller_fulfillment_order_id,
        CreateFulfillmentReturnRequest $body,
        ?string $restrictedDataToken = null
    ): CreateFulfillmentReturnResponse {
        list($response) = $this->createFulfillmentReturnWithHttpInfo($seller_fulfillment_order_id, $body, $restrictedDataToken);

        return $response;
    }

    /**
     * Operation createFulfillmentReturnWithHttpInfo.
     *
     * @param string                         $seller_fulfillment_order_id
     *                                                                    An identifier assigned by the seller to the fulfillment order at the time it was created. The seller uses their own records to find the correct &#x60;SellerFulfillmentOrderId&#x60; value based on the buyer&#39;s request to return items. (required)
     * @param CreateFulfillmentReturnRequest $body
     *                                                                    CreateFulfillmentReturnRequest parameter (required)
     * @param null|string                    $restrictedDataToken         Restricted Data Token (RDT) for accessing restricted resources (optional, required for operations that return PII)
     *
     * @return array of \SpApi\Model\fulfillment\outbound\v2020_07_01\CreateFulfillmentReturnResponse, HTTP status code, HTTP response headers (array of strings)
     *
     * @throws ApiException              on non-2xx response
     * @throws \InvalidArgumentException
     */
    public function createFulfillmentReturnWithHttpInfo(
        string $seller_fulfillment_order_id,
        CreateFulfillmentReturnRequest $body,
        ?string $restrictedDataToken = null
    ): array {
        $request = $this->createFulfillmentReturnRequest($seller_fulfillment_order_id, $body);
        if (null !== $restrictedDataToken) {
            $request = RestrictedDataTokenSigner::sign($request, $restrictedDataToken, 'FbaOutboundApi-createFulfillmentReturn');
        } else {
            $request = $this->config->sign($request);
        }

        try {
            $options = $this->createHttpClientOption();

            try {
                if ($this->rateLimiterEnabled) {
                    $this->createFulfillmentReturnRateLimiter->consume()->ensureAccepted();
                }
                $response = $this->client->send($request, $options);
            } catch (RequestException $e) {
                throw new ApiException(
                    "[{$e->getCode()}] {$e->getResponse()->getBody()}",
                    (int) $e->getCode(),
                    $e->getResponse() ? $e->getResponse()->getHeaders() : null,
                    $e->getResponse() ? (string) $e->getResponse()->getBody() : null
                );
            } catch (ConnectException $e) {
                throw new ApiException(
                    "[{$e->getCode()}] {$e->getMessage()}",
                    (int) $e->getCode(),
                    null,
                    null
                );
            }

            $statusCode = $response->getStatusCode();

            if ($statusCode < 200 || $statusCode > 299) {
                throw new ApiException(
                    sprintf(
                        '[%d] Error connecting to the API (%s)',
                        $statusCode,
                        (string) $request->getUri()
                    ),
                    $statusCode,
                    $response->getHeaders(),
                    (string) $response->getBody()
                );
            }
            if ('\SpApi\Model\fulfillment\outbound\v2020_07_01\CreateFulfillmentReturnResponse' === '\SplFileObject') {
                $content = $response->getBody(); // stream goes to serializer
            } else {
                $content = (string) $response->getBody();
                if ('\SpApi\Model\fulfillment\outbound\v2020_07_01\CreateFulfillmentReturnResponse' !== 'string') {
                    $content = json_decode($content);
                }
            }

            return [
                ObjectSerializer::deserialize($content, '\SpApi\Model\fulfillment\outbound\v2020_07_01\CreateFulfillmentReturnResponse', []),
                $response->getStatusCode(),
                $response->getHeaders(),
            ];
        } catch (ApiException $e) {
            $data = ObjectSerializer::deserialize(
                $e->getResponseBody(),
                '\SpApi\Model\fulfillment\outbound\v2020_07_01\CreateFulfillmentReturnResponse',
                $e->getResponseHeaders()
            );
            $e->setResponseObject($data);

            throw $e;
        }
    }

    /**
     * Operation createFulfillmentReturnAsync.
     *
     * @param string                         $seller_fulfillment_order_id
     *                                                                    An identifier assigned by the seller to the fulfillment order at the time it was created. The seller uses their own records to find the correct &#x60;SellerFulfillmentOrderId&#x60; value based on the buyer&#39;s request to return items. (required)
     * @param CreateFulfillmentReturnRequest $body
     *                                                                    CreateFulfillmentReturnRequest parameter (required)
     *
     * @throws \InvalidArgumentException
     */
    public function createFulfillmentReturnAsync(
        string $seller_fulfillment_order_id,
        CreateFulfillmentReturnRequest $body
    ): PromiseInterface {
        return $this->createFulfillmentReturnAsyncWithHttpInfo($seller_fulfillment_order_id, $body)
            ->then(
                function ($response) {
                    return $response[0];
                }
            )
        ;
    }

    /**
     * Operation createFulfillmentReturnAsyncWithHttpInfo.
     *
     * @param string                         $seller_fulfillment_order_id
     *                                                                    An identifier assigned by the seller to the fulfillment order at the time it was created. The seller uses their own records to find the correct &#x60;SellerFulfillmentOrderId&#x60; value based on the buyer&#39;s request to return items. (required)
     * @param CreateFulfillmentReturnRequest $body
     *                                                                    CreateFulfillmentReturnRequest parameter (required)
     *
     * @throws \InvalidArgumentException
     */
    public function createFulfillmentReturnAsyncWithHttpInfo(
        string $seller_fulfillment_order_id,
        CreateFulfillmentReturnRequest $body,
        ?string $restrictedDataToken = null
    ): PromiseInterface {
        $returnType = '\SpApi\Model\fulfillment\outbound\v2020_07_01\CreateFulfillmentReturnResponse';
        $request = $this->createFulfillmentReturnRequest($seller_fulfillment_order_id, $body);
        if (null !== $restrictedDataToken) {
            $request = RestrictedDataTokenSigner::sign($request, $restrictedDataToken, 'FbaOutboundApi-createFulfillmentReturn');
        } else {
            $request = $this->config->sign($request);
        }
        if ($this->rateLimiterEnabled) {
            $this->createFulfillmentReturnRateLimiter->consume()->ensureAccepted();
        }

        return $this->client
            ->sendAsync($request, $this->createHttpClientOption())
            ->then(
                function ($response) use ($returnType) {
                    if ('\SplFileObject' === $returnType) {
                        $content = $response->getBody(); // stream goes to serializer
                    } else {
                        $content = (string) $response->getBody();
                        if ('string' !== $returnType) {
                            $content = json_decode($content);
                        }
                    }

                    return [
                        ObjectSerializer::deserialize($content, $returnType, []),
                        $response->getStatusCode(),
                        $response->getHeaders(),
                    ];
                },
                function ($exception) {
                    $response = $exception->getResponse();
                    $statusCode = $response->getStatusCode();

                    throw new ApiException(
                        sprintf(
                            '[%d] Error connecting to the API (%s)',
                            $statusCode,
                            $exception->getRequest()->getUri()
                        ),
                        $statusCode,
                        $response->getHeaders(),
                        (string) $response->getBody()
                    );
                }
            )
        ;
    }

    /**
     * Create request for operation 'createFulfillmentReturn'.
     *
     * @param string                         $seller_fulfillment_order_id
     *                                                                    An identifier assigned by the seller to the fulfillment order at the time it was created. The seller uses their own records to find the correct &#x60;SellerFulfillmentOrderId&#x60; value based on the buyer&#39;s request to return items. (required)
     * @param CreateFulfillmentReturnRequest $body
     *                                                                    CreateFulfillmentReturnRequest parameter (required)
     *
     * @throws \InvalidArgumentException
     */
    public function createFulfillmentReturnRequest(
        string $seller_fulfillment_order_id,
        CreateFulfillmentReturnRequest $body
    ): Request {
        // verify the required parameter 'seller_fulfillment_order_id' is set
        if (null === $seller_fulfillment_order_id || (is_array($seller_fulfillment_order_id) && 0 === count($seller_fulfillment_order_id))) {
            throw new \InvalidArgumentException(
                'Missing the required parameter $seller_fulfillment_order_id when calling createFulfillmentReturn'
            );
        }
        // verify the required parameter 'body' is set
        if (null === $body || (is_array($body) && 0 === count($body))) {
            throw new \InvalidArgumentException(
                'Missing the required parameter $body when calling createFulfillmentReturn'
            );
        }

        $resourcePath = '/fba/outbound/2020-07-01/fulfillmentOrders/{sellerFulfillmentOrderId}/return';
        $formParams = [];
        $queryParams = [];
        $headerParams = [];
        $httpBody = '';
        $multipart = false;

        // path params
        if (null !== $seller_fulfillment_order_id) {
            $resourcePath = str_replace(
                '{sellerFulfillmentOrderId}',
                ObjectSerializer::toPathValue($seller_fulfillment_order_id),
                $resourcePath
            );
        }

        $headers = $this->headerSelector->selectHeaders(
            ['application/json', 'payload'],
            'application/json',
            $multipart
        );

        // for model (json/xml)
        if (isset($body)) {
            if ('application/json' === $headers['Content-Type']) {
                $httpBody = \GuzzleHttp\json_encode(ObjectSerializer::sanitizeForSerialization($body));
            } else {
                $httpBody = $body;
            }
        } elseif (count($formParams) > 0) {
            if ($multipart) {
                $multipartContents = [];
                foreach ($formParams as $formParamName => $formParamValue) {
                    $formParamValueItems = is_array($formParamValue) ? $formParamValue : [$formParamValue];
                    foreach ($formParamValueItems as $formParamValueItem) {
                        $multipartContents[] = [
                            'name' => $formParamName,
                            'contents' => $formParamValueItem,
                        ];
                    }
                }
                // for HTTP post (form)
                $httpBody = new MultipartStream($multipartContents);
            } elseif ('application/json' === $headers['Content-Type']) {
                $httpBody = \GuzzleHttp\json_encode($formParams);
            } else {
                // for HTTP post (form)
                $httpBody = ObjectSerializer::buildQuery($formParams, $this->config);
            }
        }

        $defaultHeaders = [];
        if ($this->config->getUserAgent()) {
            $defaultHeaders['User-Agent'] = $this->config->getUserAgent();
        }

        $headers = array_merge(
            $defaultHeaders,
            $headerParams,
            $headers
        );

        $query = ObjectSerializer::buildQuery($queryParams, $this->config);

        return new Request(
            'PUT',
            $this->config->getHost().$resourcePath.($query ? "?{$query}" : ''),
            $headers,
            $httpBody
        );
    }

    /**
     * Operation deliveryOffers.
     *
     * @param GetDeliveryOffersRequest $body
     *                                                      GetDeliveryOffersRequest parameter (required)
     * @param null|string              $restrictedDataToken Restricted Data Token (RDT) for accessing restricted resources (optional, required for operations that return PII)
     *
     * @throws ApiException              on non-2xx response
     * @throws \InvalidArgumentException
     */
    public function deliveryOffers(
        GetDeliveryOffersRequest $body,
        ?string $restrictedDataToken = null
    ): GetDeliveryOffersResponse {
        list($response) = $this->deliveryOffersWithHttpInfo($body, $restrictedDataToken);

        return $response;
    }

    /**
     * Operation deliveryOffersWithHttpInfo.
     *
     * @param GetDeliveryOffersRequest $body
     *                                                      GetDeliveryOffersRequest parameter (required)
     * @param null|string              $restrictedDataToken Restricted Data Token (RDT) for accessing restricted resources (optional, required for operations that return PII)
     *
     * @return array of \SpApi\Model\fulfillment\outbound\v2020_07_01\GetDeliveryOffersResponse, HTTP status code, HTTP response headers (array of strings)
     *
     * @throws ApiException              on non-2xx response
     * @throws \InvalidArgumentException
     */
    public function deliveryOffersWithHttpInfo(
        GetDeliveryOffersRequest $body,
        ?string $restrictedDataToken = null
    ): array {
        $request = $this->deliveryOffersRequest($body);
        if (null !== $restrictedDataToken) {
            $request = RestrictedDataTokenSigner::sign($request, $restrictedDataToken, 'FbaOutboundApi-deliveryOffers');
        } else {
            $request = $this->config->sign($request);
        }

        try {
            $options = $this->createHttpClientOption();

            try {
                if ($this->rateLimiterEnabled) {
                    $this->deliveryOffersRateLimiter->consume()->ensureAccepted();
                }
                $response = $this->client->send($request, $options);
            } catch (RequestException $e) {
                throw new ApiException(
                    "[{$e->getCode()}] {$e->getResponse()->getBody()}",
                    (int) $e->getCode(),
                    $e->getResponse() ? $e->getResponse()->getHeaders() : null,
                    $e->getResponse() ? (string) $e->getResponse()->getBody() : null
                );
            } catch (ConnectException $e) {
                throw new ApiException(
                    "[{$e->getCode()}] {$e->getMessage()}",
                    (int) $e->getCode(),
                    null,
                    null
                );
            }

            $statusCode = $response->getStatusCode();

            if ($statusCode < 200 || $statusCode > 299) {
                throw new ApiException(
                    sprintf(
                        '[%d] Error connecting to the API (%s)',
                        $statusCode,
                        (string) $request->getUri()
                    ),
                    $statusCode,
                    $response->getHeaders(),
                    (string) $response->getBody()
                );
            }
            if ('\SpApi\Model\fulfillment\outbound\v2020_07_01\GetDeliveryOffersResponse' === '\SplFileObject') {
                $content = $response->getBody(); // stream goes to serializer
            } else {
                $content = (string) $response->getBody();
                if ('\SpApi\Model\fulfillment\outbound\v2020_07_01\GetDeliveryOffersResponse' !== 'string') {
                    $content = json_decode($content);
                }
            }

            return [
                ObjectSerializer::deserialize($content, '\SpApi\Model\fulfillment\outbound\v2020_07_01\GetDeliveryOffersResponse', []),
                $response->getStatusCode(),
                $response->getHeaders(),
            ];
        } catch (ApiException $e) {
            $data = ObjectSerializer::deserialize(
                $e->getResponseBody(),
                '\SpApi\Model\fulfillment\outbound\v2020_07_01\GetDeliveryOffersResponse',
                $e->getResponseHeaders()
            );
            $e->setResponseObject($data);

            throw $e;
        }
    }

    /**
     * Operation deliveryOffersAsync.
     *
     * @param GetDeliveryOffersRequest $body
     *                                       GetDeliveryOffersRequest parameter (required)
     *
     * @throws \InvalidArgumentException
     */
    public function deliveryOffersAsync(
        GetDeliveryOffersRequest $body
    ): PromiseInterface {
        return $this->deliveryOffersAsyncWithHttpInfo($body)
            ->then(
                function ($response) {
                    return $response[0];
                }
            )
        ;
    }

    /**
     * Operation deliveryOffersAsyncWithHttpInfo.
     *
     * @param GetDeliveryOffersRequest $body
     *                                       GetDeliveryOffersRequest parameter (required)
     *
     * @throws \InvalidArgumentException
     */
    public function deliveryOffersAsyncWithHttpInfo(
        GetDeliveryOffersRequest $body,
        ?string $restrictedDataToken = null
    ): PromiseInterface {
        $returnType = '\SpApi\Model\fulfillment\outbound\v2020_07_01\GetDeliveryOffersResponse';
        $request = $this->deliveryOffersRequest($body);
        if (null !== $restrictedDataToken) {
            $request = RestrictedDataTokenSigner::sign($request, $restrictedDataToken, 'FbaOutboundApi-deliveryOffers');
        } else {
            $request = $this->config->sign($request);
        }
        if ($this->rateLimiterEnabled) {
            $this->deliveryOffersRateLimiter->consume()->ensureAccepted();
        }

        return $this->client
            ->sendAsync($request, $this->createHttpClientOption())
            ->then(
                function ($response) use ($returnType) {
                    if ('\SplFileObject' === $returnType) {
                        $content = $response->getBody(); // stream goes to serializer
                    } else {
                        $content = (string) $response->getBody();
                        if ('string' !== $returnType) {
                            $content = json_decode($content);
                        }
                    }

                    return [
                        ObjectSerializer::deserialize($content, $returnType, []),
                        $response->getStatusCode(),
                        $response->getHeaders(),
                    ];
                },
                function ($exception) {
                    $response = $exception->getResponse();
                    $statusCode = $response->getStatusCode();

                    throw new ApiException(
                        sprintf(
                            '[%d] Error connecting to the API (%s)',
                            $statusCode,
                            $exception->getRequest()->getUri()
                        ),
                        $statusCode,
                        $response->getHeaders(),
                        (string) $response->getBody()
                    );
                }
            )
        ;
    }

    /**
     * Create request for operation 'deliveryOffers'.
     *
     * @param GetDeliveryOffersRequest $body
     *                                       GetDeliveryOffersRequest parameter (required)
     *
     * @throws \InvalidArgumentException
     */
    public function deliveryOffersRequest(
        GetDeliveryOffersRequest $body
    ): Request {
        // verify the required parameter 'body' is set
        if (null === $body || (is_array($body) && 0 === count($body))) {
            throw new \InvalidArgumentException(
                'Missing the required parameter $body when calling deliveryOffers'
            );
        }

        $resourcePath = '/fba/outbound/2020-07-01/deliveryOffers';
        $formParams = [];
        $queryParams = [];
        $headerParams = [];
        $httpBody = '';
        $multipart = false;

        $headers = $this->headerSelector->selectHeaders(
            ['application/json', 'payload'],
            'application/json',
            $multipart
        );

        // for model (json/xml)
        if (isset($body)) {
            if ('application/json' === $headers['Content-Type']) {
                $httpBody = \GuzzleHttp\json_encode(ObjectSerializer::sanitizeForSerialization($body));
            } else {
                $httpBody = $body;
            }
        } elseif (count($formParams) > 0) {
            if ($multipart) {
                $multipartContents = [];
                foreach ($formParams as $formParamName => $formParamValue) {
                    $formParamValueItems = is_array($formParamValue) ? $formParamValue : [$formParamValue];
                    foreach ($formParamValueItems as $formParamValueItem) {
                        $multipartContents[] = [
                            'name' => $formParamName,
                            'contents' => $formParamValueItem,
                        ];
                    }
                }
                // for HTTP post (form)
                $httpBody = new MultipartStream($multipartContents);
            } elseif ('application/json' === $headers['Content-Type']) {
                $httpBody = \GuzzleHttp\json_encode($formParams);
            } else {
                // for HTTP post (form)
                $httpBody = ObjectSerializer::buildQuery($formParams, $this->config);
            }
        }

        $defaultHeaders = [];
        if ($this->config->getUserAgent()) {
            $defaultHeaders['User-Agent'] = $this->config->getUserAgent();
        }

        $headers = array_merge(
            $defaultHeaders,
            $headerParams,
            $headers
        );

        $query = ObjectSerializer::buildQuery($queryParams, $this->config);

        return new Request(
            'POST',
            $this->config->getHost().$resourcePath.($query ? "?{$query}" : ''),
            $headers,
            $httpBody
        );
    }

    /**
     * Operation getFeatureInventory.
     *
     * @param string         $marketplace_id
     *                                            The marketplace for which to return a list of the inventory that is eligible for the specified feature. (required)
     * @param string         $feature_name
     *                                            The name of the feature for which to return a list of eligible inventory. (required)
     * @param null|string    $next_token
     *                                            A string token returned in the response to your previous request that is used to return the next response page. A value of null will return the first page. (optional)
     * @param null|\DateTime $query_start_date
     *                                            A date that you can use to select inventory that has been updated since a specified date. An update is defined as any change in feature-enabled inventory availability. The date must be in the format yyyy-MM-ddTHH:mm:ss.sssZ (optional)
     * @param null|string    $restrictedDataToken Restricted Data Token (RDT) for accessing restricted resources (optional, required for operations that return PII)
     *
     * @throws ApiException              on non-2xx response
     * @throws \InvalidArgumentException
     */
    public function getFeatureInventory(
        string $marketplace_id,
        string $feature_name,
        ?string $next_token = null,
        ?\DateTime $query_start_date = null,
        ?string $restrictedDataToken = null
    ): GetFeatureInventoryResponse {
        list($response) = $this->getFeatureInventoryWithHttpInfo($marketplace_id, $feature_name, $next_token, $query_start_date, $restrictedDataToken);

        return $response;
    }

    /**
     * Operation getFeatureInventoryWithHttpInfo.
     *
     * @param string         $marketplace_id
     *                                            The marketplace for which to return a list of the inventory that is eligible for the specified feature. (required)
     * @param string         $feature_name
     *                                            The name of the feature for which to return a list of eligible inventory. (required)
     * @param null|string    $next_token
     *                                            A string token returned in the response to your previous request that is used to return the next response page. A value of null will return the first page. (optional)
     * @param null|\DateTime $query_start_date
     *                                            A date that you can use to select inventory that has been updated since a specified date. An update is defined as any change in feature-enabled inventory availability. The date must be in the format yyyy-MM-ddTHH:mm:ss.sssZ (optional)
     * @param null|string    $restrictedDataToken Restricted Data Token (RDT) for accessing restricted resources (optional, required for operations that return PII)
     *
     * @return array of \SpApi\Model\fulfillment\outbound\v2020_07_01\GetFeatureInventoryResponse, HTTP status code, HTTP response headers (array of strings)
     *
     * @throws ApiException              on non-2xx response
     * @throws \InvalidArgumentException
     */
    public function getFeatureInventoryWithHttpInfo(
        string $marketplace_id,
        string $feature_name,
        ?string $next_token = null,
        ?\DateTime $query_start_date = null,
        ?string $restrictedDataToken = null
    ): array {
        $request = $this->getFeatureInventoryRequest($marketplace_id, $feature_name, $next_token, $query_start_date);
        if (null !== $restrictedDataToken) {
            $request = RestrictedDataTokenSigner::sign($request, $restrictedDataToken, 'FbaOutboundApi-getFeatureInventory');
        } else {
            $request = $this->config->sign($request);
        }

        try {
            $options = $this->createHttpClientOption();

            try {
                if ($this->rateLimiterEnabled) {
                    $this->getFeatureInventoryRateLimiter->consume()->ensureAccepted();
                }
                $response = $this->client->send($request, $options);
            } catch (RequestException $e) {
                throw new ApiException(
                    "[{$e->getCode()}] {$e->getResponse()->getBody()}",
                    (int) $e->getCode(),
                    $e->getResponse() ? $e->getResponse()->getHeaders() : null,
                    $e->getResponse() ? (string) $e->getResponse()->getBody() : null
                );
            } catch (ConnectException $e) {
                throw new ApiException(
                    "[{$e->getCode()}] {$e->getMessage()}",
                    (int) $e->getCode(),
                    null,
                    null
                );
            }

            $statusCode = $response->getStatusCode();

            if ($statusCode < 200 || $statusCode > 299) {
                throw new ApiException(
                    sprintf(
                        '[%d] Error connecting to the API (%s)',
                        $statusCode,
                        (string) $request->getUri()
                    ),
                    $statusCode,
                    $response->getHeaders(),
                    (string) $response->getBody()
                );
            }
            if ('\SpApi\Model\fulfillment\outbound\v2020_07_01\GetFeatureInventoryResponse' === '\SplFileObject') {
                $content = $response->getBody(); // stream goes to serializer
            } else {
                $content = (string) $response->getBody();
                if ('\SpApi\Model\fulfillment\outbound\v2020_07_01\GetFeatureInventoryResponse' !== 'string') {
                    $content = json_decode($content);
                }
            }

            return [
                ObjectSerializer::deserialize($content, '\SpApi\Model\fulfillment\outbound\v2020_07_01\GetFeatureInventoryResponse', []),
                $response->getStatusCode(),
                $response->getHeaders(),
            ];
        } catch (ApiException $e) {
            $data = ObjectSerializer::deserialize(
                $e->getResponseBody(),
                '\SpApi\Model\fulfillment\outbound\v2020_07_01\GetFeatureInventoryResponse',
                $e->getResponseHeaders()
            );
            $e->setResponseObject($data);

            throw $e;
        }
    }

    /**
     * Operation getFeatureInventoryAsync.
     *
     * @param string         $marketplace_id
     *                                         The marketplace for which to return a list of the inventory that is eligible for the specified feature. (required)
     * @param string         $feature_name
     *                                         The name of the feature for which to return a list of eligible inventory. (required)
     * @param null|string    $next_token
     *                                         A string token returned in the response to your previous request that is used to return the next response page. A value of null will return the first page. (optional)
     * @param null|\DateTime $query_start_date
     *                                         A date that you can use to select inventory that has been updated since a specified date. An update is defined as any change in feature-enabled inventory availability. The date must be in the format yyyy-MM-ddTHH:mm:ss.sssZ (optional)
     *
     * @throws \InvalidArgumentException
     */
    public function getFeatureInventoryAsync(
        string $marketplace_id,
        string $feature_name,
        ?string $next_token = null,
        ?\DateTime $query_start_date = null
    ): PromiseInterface {
        return $this->getFeatureInventoryAsyncWithHttpInfo($marketplace_id, $feature_name, $next_token, $query_start_date)
            ->then(
                function ($response) {
                    return $response[0];
                }
            )
        ;
    }

    /**
     * Operation getFeatureInventoryAsyncWithHttpInfo.
     *
     * @param string         $marketplace_id
     *                                         The marketplace for which to return a list of the inventory that is eligible for the specified feature. (required)
     * @param string         $feature_name
     *                                         The name of the feature for which to return a list of eligible inventory. (required)
     * @param null|string    $next_token
     *                                         A string token returned in the response to your previous request that is used to return the next response page. A value of null will return the first page. (optional)
     * @param null|\DateTime $query_start_date
     *                                         A date that you can use to select inventory that has been updated since a specified date. An update is defined as any change in feature-enabled inventory availability. The date must be in the format yyyy-MM-ddTHH:mm:ss.sssZ (optional)
     *
     * @throws \InvalidArgumentException
     */
    public function getFeatureInventoryAsyncWithHttpInfo(
        string $marketplace_id,
        string $feature_name,
        ?string $next_token = null,
        ?\DateTime $query_start_date = null,
        ?string $restrictedDataToken = null
    ): PromiseInterface {
        $returnType = '\SpApi\Model\fulfillment\outbound\v2020_07_01\GetFeatureInventoryResponse';
        $request = $this->getFeatureInventoryRequest($marketplace_id, $feature_name, $next_token, $query_start_date);
        if (null !== $restrictedDataToken) {
            $request = RestrictedDataTokenSigner::sign($request, $restrictedDataToken, 'FbaOutboundApi-getFeatureInventory');
        } else {
            $request = $this->config->sign($request);
        }
        if ($this->rateLimiterEnabled) {
            $this->getFeatureInventoryRateLimiter->consume()->ensureAccepted();
        }

        return $this->client
            ->sendAsync($request, $this->createHttpClientOption())
            ->then(
                function ($response) use ($returnType) {
                    if ('\SplFileObject' === $returnType) {
                        $content = $response->getBody(); // stream goes to serializer
                    } else {
                        $content = (string) $response->getBody();
                        if ('string' !== $returnType) {
                            $content = json_decode($content);
                        }
                    }

                    return [
                        ObjectSerializer::deserialize($content, $returnType, []),
                        $response->getStatusCode(),
                        $response->getHeaders(),
                    ];
                },
                function ($exception) {
                    $response = $exception->getResponse();
                    $statusCode = $response->getStatusCode();

                    throw new ApiException(
                        sprintf(
                            '[%d] Error connecting to the API (%s)',
                            $statusCode,
                            $exception->getRequest()->getUri()
                        ),
                        $statusCode,
                        $response->getHeaders(),
                        (string) $response->getBody()
                    );
                }
            )
        ;
    }

    /**
     * Create request for operation 'getFeatureInventory'.
     *
     * @param string         $marketplace_id
     *                                         The marketplace for which to return a list of the inventory that is eligible for the specified feature. (required)
     * @param string         $feature_name
     *                                         The name of the feature for which to return a list of eligible inventory. (required)
     * @param null|string    $next_token
     *                                         A string token returned in the response to your previous request that is used to return the next response page. A value of null will return the first page. (optional)
     * @param null|\DateTime $query_start_date
     *                                         A date that you can use to select inventory that has been updated since a specified date. An update is defined as any change in feature-enabled inventory availability. The date must be in the format yyyy-MM-ddTHH:mm:ss.sssZ (optional)
     *
     * @throws \InvalidArgumentException
     */
    public function getFeatureInventoryRequest(
        string $marketplace_id,
        string $feature_name,
        ?string $next_token = null,
        ?\DateTime $query_start_date = null
    ): Request {
        // verify the required parameter 'marketplace_id' is set
        if (null === $marketplace_id || (is_array($marketplace_id) && 0 === count($marketplace_id))) {
            throw new \InvalidArgumentException(
                'Missing the required parameter $marketplace_id when calling getFeatureInventory'
            );
        }
        // verify the required parameter 'feature_name' is set
        if (null === $feature_name || (is_array($feature_name) && 0 === count($feature_name))) {
            throw new \InvalidArgumentException(
                'Missing the required parameter $feature_name when calling getFeatureInventory'
            );
        }

        $resourcePath = '/fba/outbound/2020-07-01/features/inventory/{featureName}';
        $formParams = [];
        $queryParams = [];
        $headerParams = [];
        $httpBody = '';
        $multipart = false;

        // query params
        $queryParams = array_merge($queryParams, ObjectSerializer::toQueryValue(
            $marketplace_id,
            'marketplaceId', // param base name
            'string', // openApiType
            '', // style
            false, // explode
            true, // required
            $this->config
        ) ?? []);
        // query params
        $queryParams = array_merge($queryParams, ObjectSerializer::toQueryValue(
            $next_token,
            'nextToken', // param base name
            'string', // openApiType
            '', // style
            false, // explode
            false, // required
            $this->config
        ) ?? []);
        // query params
        $queryParams = array_merge($queryParams, ObjectSerializer::toQueryValue(
            $query_start_date,
            'queryStartDate', // param base name
            'string', // openApiType
            '', // style
            false, // explode
            false, // required
            $this->config
        ) ?? []);

        // path params
        if (null !== $feature_name) {
            $resourcePath = str_replace(
                '{featureName}',
                ObjectSerializer::toPathValue($feature_name),
                $resourcePath
            );
        }

        $headers = $this->headerSelector->selectHeaders(
            ['application/json', 'payload'],
            '',
            $multipart
        );

        // for model (json/xml)
        if (count($formParams) > 0) {
            if ($multipart) {
                $multipartContents = [];
                foreach ($formParams as $formParamName => $formParamValue) {
                    $formParamValueItems = is_array($formParamValue) ? $formParamValue : [$formParamValue];
                    foreach ($formParamValueItems as $formParamValueItem) {
                        $multipartContents[] = [
                            'name' => $formParamName,
                            'contents' => $formParamValueItem,
                        ];
                    }
                }
                // for HTTP post (form)
                $httpBody = new MultipartStream($multipartContents);
            } elseif ('application/json' === $headers['Content-Type']) {
                $httpBody = \GuzzleHttp\json_encode($formParams);
            } else {
                // for HTTP post (form)
                $httpBody = ObjectSerializer::buildQuery($formParams, $this->config);
            }
        }

        $defaultHeaders = [];
        if ($this->config->getUserAgent()) {
            $defaultHeaders['User-Agent'] = $this->config->getUserAgent();
        }

        $headers = array_merge(
            $defaultHeaders,
            $headerParams,
            $headers
        );

        $query = ObjectSerializer::buildQuery($queryParams, $this->config);

        return new Request(
            'GET',
            $this->config->getHost().$resourcePath.($query ? "?{$query}" : ''),
            $headers,
            $httpBody
        );
    }

    /**
     * Operation getFeatureSKU.
     *
     * @param string      $marketplace_id
     *                                         The marketplace for which to return the count. (required)
     * @param string      $feature_name
     *                                         The name of the feature. (required)
     * @param string      $seller_sku
     *                                         Used to identify an item in the given marketplace. &#x60;SellerSKU&#x60; is qualified by the seller&#39;s &#x60;SellerId&#x60;, which is included with every operation that you submit. (required)
     * @param null|string $restrictedDataToken Restricted Data Token (RDT) for accessing restricted resources (optional, required for operations that return PII)
     *
     * @throws ApiException              on non-2xx response
     * @throws \InvalidArgumentException
     */
    public function getFeatureSKU(
        string $marketplace_id,
        string $feature_name,
        string $seller_sku,
        ?string $restrictedDataToken = null
    ): GetFeatureSkuResponse {
        list($response) = $this->getFeatureSKUWithHttpInfo($marketplace_id, $feature_name, $seller_sku, $restrictedDataToken);

        return $response;
    }

    /**
     * Operation getFeatureSKUWithHttpInfo.
     *
     * @param string      $marketplace_id
     *                                         The marketplace for which to return the count. (required)
     * @param string      $feature_name
     *                                         The name of the feature. (required)
     * @param string      $seller_sku
     *                                         Used to identify an item in the given marketplace. &#x60;SellerSKU&#x60; is qualified by the seller&#39;s &#x60;SellerId&#x60;, which is included with every operation that you submit. (required)
     * @param null|string $restrictedDataToken Restricted Data Token (RDT) for accessing restricted resources (optional, required for operations that return PII)
     *
     * @return array of \SpApi\Model\fulfillment\outbound\v2020_07_01\GetFeatureSkuResponse, HTTP status code, HTTP response headers (array of strings)
     *
     * @throws ApiException              on non-2xx response
     * @throws \InvalidArgumentException
     */
    public function getFeatureSKUWithHttpInfo(
        string $marketplace_id,
        string $feature_name,
        string $seller_sku,
        ?string $restrictedDataToken = null
    ): array {
        $request = $this->getFeatureSKURequest($marketplace_id, $feature_name, $seller_sku);
        if (null !== $restrictedDataToken) {
            $request = RestrictedDataTokenSigner::sign($request, $restrictedDataToken, 'FbaOutboundApi-getFeatureSKU');
        } else {
            $request = $this->config->sign($request);
        }

        try {
            $options = $this->createHttpClientOption();

            try {
                if ($this->rateLimiterEnabled) {
                    $this->getFeatureSKURateLimiter->consume()->ensureAccepted();
                }
                $response = $this->client->send($request, $options);
            } catch (RequestException $e) {
                throw new ApiException(
                    "[{$e->getCode()}] {$e->getResponse()->getBody()}",
                    (int) $e->getCode(),
                    $e->getResponse() ? $e->getResponse()->getHeaders() : null,
                    $e->getResponse() ? (string) $e->getResponse()->getBody() : null
                );
            } catch (ConnectException $e) {
                throw new ApiException(
                    "[{$e->getCode()}] {$e->getMessage()}",
                    (int) $e->getCode(),
                    null,
                    null
                );
            }

            $statusCode = $response->getStatusCode();

            if ($statusCode < 200 || $statusCode > 299) {
                throw new ApiException(
                    sprintf(
                        '[%d] Error connecting to the API (%s)',
                        $statusCode,
                        (string) $request->getUri()
                    ),
                    $statusCode,
                    $response->getHeaders(),
                    (string) $response->getBody()
                );
            }
            if ('\SpApi\Model\fulfillment\outbound\v2020_07_01\GetFeatureSkuResponse' === '\SplFileObject') {
                $content = $response->getBody(); // stream goes to serializer
            } else {
                $content = (string) $response->getBody();
                if ('\SpApi\Model\fulfillment\outbound\v2020_07_01\GetFeatureSkuResponse' !== 'string') {
                    $content = json_decode($content);
                }
            }

            return [
                ObjectSerializer::deserialize($content, '\SpApi\Model\fulfillment\outbound\v2020_07_01\GetFeatureSkuResponse', []),
                $response->getStatusCode(),
                $response->getHeaders(),
            ];
        } catch (ApiException $e) {
            $data = ObjectSerializer::deserialize(
                $e->getResponseBody(),
                '\SpApi\Model\fulfillment\outbound\v2020_07_01\GetFeatureSkuResponse',
                $e->getResponseHeaders()
            );
            $e->setResponseObject($data);

            throw $e;
        }
    }

    /**
     * Operation getFeatureSKUAsync.
     *
     * @param string $marketplace_id
     *                               The marketplace for which to return the count. (required)
     * @param string $feature_name
     *                               The name of the feature. (required)
     * @param string $seller_sku
     *                               Used to identify an item in the given marketplace. &#x60;SellerSKU&#x60; is qualified by the seller&#39;s &#x60;SellerId&#x60;, which is included with every operation that you submit. (required)
     *
     * @throws \InvalidArgumentException
     */
    public function getFeatureSKUAsync(
        string $marketplace_id,
        string $feature_name,
        string $seller_sku
    ): PromiseInterface {
        return $this->getFeatureSKUAsyncWithHttpInfo($marketplace_id, $feature_name, $seller_sku)
            ->then(
                function ($response) {
                    return $response[0];
                }
            )
        ;
    }

    /**
     * Operation getFeatureSKUAsyncWithHttpInfo.
     *
     * @param string $marketplace_id
     *                               The marketplace for which to return the count. (required)
     * @param string $feature_name
     *                               The name of the feature. (required)
     * @param string $seller_sku
     *                               Used to identify an item in the given marketplace. &#x60;SellerSKU&#x60; is qualified by the seller&#39;s &#x60;SellerId&#x60;, which is included with every operation that you submit. (required)
     *
     * @throws \InvalidArgumentException
     */
    public function getFeatureSKUAsyncWithHttpInfo(
        string $marketplace_id,
        string $feature_name,
        string $seller_sku,
        ?string $restrictedDataToken = null
    ): PromiseInterface {
        $returnType = '\SpApi\Model\fulfillment\outbound\v2020_07_01\GetFeatureSkuResponse';
        $request = $this->getFeatureSKURequest($marketplace_id, $feature_name, $seller_sku);
        if (null !== $restrictedDataToken) {
            $request = RestrictedDataTokenSigner::sign($request, $restrictedDataToken, 'FbaOutboundApi-getFeatureSKU');
        } else {
            $request = $this->config->sign($request);
        }
        if ($this->rateLimiterEnabled) {
            $this->getFeatureSKURateLimiter->consume()->ensureAccepted();
        }

        return $this->client
            ->sendAsync($request, $this->createHttpClientOption())
            ->then(
                function ($response) use ($returnType) {
                    if ('\SplFileObject' === $returnType) {
                        $content = $response->getBody(); // stream goes to serializer
                    } else {
                        $content = (string) $response->getBody();
                        if ('string' !== $returnType) {
                            $content = json_decode($content);
                        }
                    }

                    return [
                        ObjectSerializer::deserialize($content, $returnType, []),
                        $response->getStatusCode(),
                        $response->getHeaders(),
                    ];
                },
                function ($exception) {
                    $response = $exception->getResponse();
                    $statusCode = $response->getStatusCode();

                    throw new ApiException(
                        sprintf(
                            '[%d] Error connecting to the API (%s)',
                            $statusCode,
                            $exception->getRequest()->getUri()
                        ),
                        $statusCode,
                        $response->getHeaders(),
                        (string) $response->getBody()
                    );
                }
            )
        ;
    }

    /**
     * Create request for operation 'getFeatureSKU'.
     *
     * @param string $marketplace_id
     *                               The marketplace for which to return the count. (required)
     * @param string $feature_name
     *                               The name of the feature. (required)
     * @param string $seller_sku
     *                               Used to identify an item in the given marketplace. &#x60;SellerSKU&#x60; is qualified by the seller&#39;s &#x60;SellerId&#x60;, which is included with every operation that you submit. (required)
     *
     * @throws \InvalidArgumentException
     */
    public function getFeatureSKURequest(
        string $marketplace_id,
        string $feature_name,
        string $seller_sku
    ): Request {
        // verify the required parameter 'marketplace_id' is set
        if (null === $marketplace_id || (is_array($marketplace_id) && 0 === count($marketplace_id))) {
            throw new \InvalidArgumentException(
                'Missing the required parameter $marketplace_id when calling getFeatureSKU'
            );
        }
        // verify the required parameter 'feature_name' is set
        if (null === $feature_name || (is_array($feature_name) && 0 === count($feature_name))) {
            throw new \InvalidArgumentException(
                'Missing the required parameter $feature_name when calling getFeatureSKU'
            );
        }
        // verify the required parameter 'seller_sku' is set
        if (null === $seller_sku || (is_array($seller_sku) && 0 === count($seller_sku))) {
            throw new \InvalidArgumentException(
                'Missing the required parameter $seller_sku when calling getFeatureSKU'
            );
        }

        $resourcePath = '/fba/outbound/2020-07-01/features/inventory/{featureName}/{sellerSku}';
        $formParams = [];
        $queryParams = [];
        $headerParams = [];
        $httpBody = '';
        $multipart = false;

        // query params
        $queryParams = array_merge($queryParams, ObjectSerializer::toQueryValue(
            $marketplace_id,
            'marketplaceId', // param base name
            'string', // openApiType
            '', // style
            false, // explode
            true, // required
            $this->config
        ) ?? []);

        // path params
        if (null !== $feature_name) {
            $resourcePath = str_replace(
                '{featureName}',
                ObjectSerializer::toPathValue($feature_name),
                $resourcePath
            );
        }
        // path params
        if (null !== $seller_sku) {
            $resourcePath = str_replace(
                '{sellerSku}',
                ObjectSerializer::toPathValue($seller_sku),
                $resourcePath
            );
        }

        $headers = $this->headerSelector->selectHeaders(
            ['application/json', 'payload'],
            '',
            $multipart
        );

        // for model (json/xml)
        if (count($formParams) > 0) {
            if ($multipart) {
                $multipartContents = [];
                foreach ($formParams as $formParamName => $formParamValue) {
                    $formParamValueItems = is_array($formParamValue) ? $formParamValue : [$formParamValue];
                    foreach ($formParamValueItems as $formParamValueItem) {
                        $multipartContents[] = [
                            'name' => $formParamName,
                            'contents' => $formParamValueItem,
                        ];
                    }
                }
                // for HTTP post (form)
                $httpBody = new MultipartStream($multipartContents);
            } elseif ('application/json' === $headers['Content-Type']) {
                $httpBody = \GuzzleHttp\json_encode($formParams);
            } else {
                // for HTTP post (form)
                $httpBody = ObjectSerializer::buildQuery($formParams, $this->config);
            }
        }

        $defaultHeaders = [];
        if ($this->config->getUserAgent()) {
            $defaultHeaders['User-Agent'] = $this->config->getUserAgent();
        }

        $headers = array_merge(
            $defaultHeaders,
            $headerParams,
            $headers
        );

        $query = ObjectSerializer::buildQuery($queryParams, $this->config);

        return new Request(
            'GET',
            $this->config->getHost().$resourcePath.($query ? "?{$query}" : ''),
            $headers,
            $httpBody
        );
    }

    /**
     * Operation getFeatures.
     *
     * @param string      $marketplace_id
     *                                         The marketplace for which to return the list of features. (required)
     * @param null|string $restrictedDataToken Restricted Data Token (RDT) for accessing restricted resources (optional, required for operations that return PII)
     *
     * @throws ApiException              on non-2xx response
     * @throws \InvalidArgumentException
     */
    public function getFeatures(
        string $marketplace_id,
        ?string $restrictedDataToken = null
    ): GetFeaturesResponse {
        list($response) = $this->getFeaturesWithHttpInfo($marketplace_id, $restrictedDataToken);

        return $response;
    }

    /**
     * Operation getFeaturesWithHttpInfo.
     *
     * @param string      $marketplace_id
     *                                         The marketplace for which to return the list of features. (required)
     * @param null|string $restrictedDataToken Restricted Data Token (RDT) for accessing restricted resources (optional, required for operations that return PII)
     *
     * @return array of \SpApi\Model\fulfillment\outbound\v2020_07_01\GetFeaturesResponse, HTTP status code, HTTP response headers (array of strings)
     *
     * @throws ApiException              on non-2xx response
     * @throws \InvalidArgumentException
     */
    public function getFeaturesWithHttpInfo(
        string $marketplace_id,
        ?string $restrictedDataToken = null
    ): array {
        $request = $this->getFeaturesRequest($marketplace_id);
        if (null !== $restrictedDataToken) {
            $request = RestrictedDataTokenSigner::sign($request, $restrictedDataToken, 'FbaOutboundApi-getFeatures');
        } else {
            $request = $this->config->sign($request);
        }

        try {
            $options = $this->createHttpClientOption();

            try {
                if ($this->rateLimiterEnabled) {
                    $this->getFeaturesRateLimiter->consume()->ensureAccepted();
                }
                $response = $this->client->send($request, $options);
            } catch (RequestException $e) {
                throw new ApiException(
                    "[{$e->getCode()}] {$e->getResponse()->getBody()}",
                    (int) $e->getCode(),
                    $e->getResponse() ? $e->getResponse()->getHeaders() : null,
                    $e->getResponse() ? (string) $e->getResponse()->getBody() : null
                );
            } catch (ConnectException $e) {
                throw new ApiException(
                    "[{$e->getCode()}] {$e->getMessage()}",
                    (int) $e->getCode(),
                    null,
                    null
                );
            }

            $statusCode = $response->getStatusCode();

            if ($statusCode < 200 || $statusCode > 299) {
                throw new ApiException(
                    sprintf(
                        '[%d] Error connecting to the API (%s)',
                        $statusCode,
                        (string) $request->getUri()
                    ),
                    $statusCode,
                    $response->getHeaders(),
                    (string) $response->getBody()
                );
            }
            if ('\SpApi\Model\fulfillment\outbound\v2020_07_01\GetFeaturesResponse' === '\SplFileObject') {
                $content = $response->getBody(); // stream goes to serializer
            } else {
                $content = (string) $response->getBody();
                if ('\SpApi\Model\fulfillment\outbound\v2020_07_01\GetFeaturesResponse' !== 'string') {
                    $content = json_decode($content);
                }
            }

            return [
                ObjectSerializer::deserialize($content, '\SpApi\Model\fulfillment\outbound\v2020_07_01\GetFeaturesResponse', []),
                $response->getStatusCode(),
                $response->getHeaders(),
            ];
        } catch (ApiException $e) {
            $data = ObjectSerializer::deserialize(
                $e->getResponseBody(),
                '\SpApi\Model\fulfillment\outbound\v2020_07_01\GetFeaturesResponse',
                $e->getResponseHeaders()
            );
            $e->setResponseObject($data);

            throw $e;
        }
    }

    /**
     * Operation getFeaturesAsync.
     *
     * @param string $marketplace_id
     *                               The marketplace for which to return the list of features. (required)
     *
     * @throws \InvalidArgumentException
     */
    public function getFeaturesAsync(
        string $marketplace_id
    ): PromiseInterface {
        return $this->getFeaturesAsyncWithHttpInfo($marketplace_id)
            ->then(
                function ($response) {
                    return $response[0];
                }
            )
        ;
    }

    /**
     * Operation getFeaturesAsyncWithHttpInfo.
     *
     * @param string $marketplace_id
     *                               The marketplace for which to return the list of features. (required)
     *
     * @throws \InvalidArgumentException
     */
    public function getFeaturesAsyncWithHttpInfo(
        string $marketplace_id,
        ?string $restrictedDataToken = null
    ): PromiseInterface {
        $returnType = '\SpApi\Model\fulfillment\outbound\v2020_07_01\GetFeaturesResponse';
        $request = $this->getFeaturesRequest($marketplace_id);
        if (null !== $restrictedDataToken) {
            $request = RestrictedDataTokenSigner::sign($request, $restrictedDataToken, 'FbaOutboundApi-getFeatures');
        } else {
            $request = $this->config->sign($request);
        }
        if ($this->rateLimiterEnabled) {
            $this->getFeaturesRateLimiter->consume()->ensureAccepted();
        }

        return $this->client
            ->sendAsync($request, $this->createHttpClientOption())
            ->then(
                function ($response) use ($returnType) {
                    if ('\SplFileObject' === $returnType) {
                        $content = $response->getBody(); // stream goes to serializer
                    } else {
                        $content = (string) $response->getBody();
                        if ('string' !== $returnType) {
                            $content = json_decode($content);
                        }
                    }

                    return [
                        ObjectSerializer::deserialize($content, $returnType, []),
                        $response->getStatusCode(),
                        $response->getHeaders(),
                    ];
                },
                function ($exception) {
                    $response = $exception->getResponse();
                    $statusCode = $response->getStatusCode();

                    throw new ApiException(
                        sprintf(
                            '[%d] Error connecting to the API (%s)',
                            $statusCode,
                            $exception->getRequest()->getUri()
                        ),
                        $statusCode,
                        $response->getHeaders(),
                        (string) $response->getBody()
                    );
                }
            )
        ;
    }

    /**
     * Create request for operation 'getFeatures'.
     *
     * @param string $marketplace_id
     *                               The marketplace for which to return the list of features. (required)
     *
     * @throws \InvalidArgumentException
     */
    public function getFeaturesRequest(
        string $marketplace_id
    ): Request {
        // verify the required parameter 'marketplace_id' is set
        if (null === $marketplace_id || (is_array($marketplace_id) && 0 === count($marketplace_id))) {
            throw new \InvalidArgumentException(
                'Missing the required parameter $marketplace_id when calling getFeatures'
            );
        }

        $resourcePath = '/fba/outbound/2020-07-01/features';
        $formParams = [];
        $queryParams = [];
        $headerParams = [];
        $httpBody = '';
        $multipart = false;

        // query params
        $queryParams = array_merge($queryParams, ObjectSerializer::toQueryValue(
            $marketplace_id,
            'marketplaceId', // param base name
            'string', // openApiType
            '', // style
            false, // explode
            true, // required
            $this->config
        ) ?? []);

        $headers = $this->headerSelector->selectHeaders(
            ['application/json', 'payload'],
            '',
            $multipart
        );

        // for model (json/xml)
        if (count($formParams) > 0) {
            if ($multipart) {
                $multipartContents = [];
                foreach ($formParams as $formParamName => $formParamValue) {
                    $formParamValueItems = is_array($formParamValue) ? $formParamValue : [$formParamValue];
                    foreach ($formParamValueItems as $formParamValueItem) {
                        $multipartContents[] = [
                            'name' => $formParamName,
                            'contents' => $formParamValueItem,
                        ];
                    }
                }
                // for HTTP post (form)
                $httpBody = new MultipartStream($multipartContents);
            } elseif ('application/json' === $headers['Content-Type']) {
                $httpBody = \GuzzleHttp\json_encode($formParams);
            } else {
                // for HTTP post (form)
                $httpBody = ObjectSerializer::buildQuery($formParams, $this->config);
            }
        }

        $defaultHeaders = [];
        if ($this->config->getUserAgent()) {
            $defaultHeaders['User-Agent'] = $this->config->getUserAgent();
        }

        $headers = array_merge(
            $defaultHeaders,
            $headerParams,
            $headers
        );

        $query = ObjectSerializer::buildQuery($queryParams, $this->config);

        return new Request(
            'GET',
            $this->config->getHost().$resourcePath.($query ? "?{$query}" : ''),
            $headers,
            $httpBody
        );
    }

    /**
     * Operation getFulfillmentOrder.
     *
     * @param string      $seller_fulfillment_order_id
     *                                                 The identifier assigned to the item by the seller when the fulfillment order was created. (required)
     * @param null|string $restrictedDataToken         Restricted Data Token (RDT) for accessing restricted resources (optional, required for operations that return PII)
     *
     * @throws ApiException              on non-2xx response
     * @throws \InvalidArgumentException
     */
    public function getFulfillmentOrder(
        string $seller_fulfillment_order_id,
        ?string $restrictedDataToken = null
    ): GetFulfillmentOrderResponse {
        list($response) = $this->getFulfillmentOrderWithHttpInfo($seller_fulfillment_order_id, $restrictedDataToken);

        return $response;
    }

    /**
     * Operation getFulfillmentOrderWithHttpInfo.
     *
     * @param string      $seller_fulfillment_order_id
     *                                                 The identifier assigned to the item by the seller when the fulfillment order was created. (required)
     * @param null|string $restrictedDataToken         Restricted Data Token (RDT) for accessing restricted resources (optional, required for operations that return PII)
     *
     * @return array of \SpApi\Model\fulfillment\outbound\v2020_07_01\GetFulfillmentOrderResponse, HTTP status code, HTTP response headers (array of strings)
     *
     * @throws ApiException              on non-2xx response
     * @throws \InvalidArgumentException
     */
    public function getFulfillmentOrderWithHttpInfo(
        string $seller_fulfillment_order_id,
        ?string $restrictedDataToken = null
    ): array {
        $request = $this->getFulfillmentOrderRequest($seller_fulfillment_order_id);
        if (null !== $restrictedDataToken) {
            $request = RestrictedDataTokenSigner::sign($request, $restrictedDataToken, 'FbaOutboundApi-getFulfillmentOrder');
        } else {
            $request = $this->config->sign($request);
        }

        try {
            $options = $this->createHttpClientOption();

            try {
                if ($this->rateLimiterEnabled) {
                    $this->getFulfillmentOrderRateLimiter->consume()->ensureAccepted();
                }
                $response = $this->client->send($request, $options);
            } catch (RequestException $e) {
                throw new ApiException(
                    "[{$e->getCode()}] {$e->getResponse()->getBody()}",
                    (int) $e->getCode(),
                    $e->getResponse() ? $e->getResponse()->getHeaders() : null,
                    $e->getResponse() ? (string) $e->getResponse()->getBody() : null
                );
            } catch (ConnectException $e) {
                throw new ApiException(
                    "[{$e->getCode()}] {$e->getMessage()}",
                    (int) $e->getCode(),
                    null,
                    null
                );
            }

            $statusCode = $response->getStatusCode();

            if ($statusCode < 200 || $statusCode > 299) {
                throw new ApiException(
                    sprintf(
                        '[%d] Error connecting to the API (%s)',
                        $statusCode,
                        (string) $request->getUri()
                    ),
                    $statusCode,
                    $response->getHeaders(),
                    (string) $response->getBody()
                );
            }
            if ('\SpApi\Model\fulfillment\outbound\v2020_07_01\GetFulfillmentOrderResponse' === '\SplFileObject') {
                $content = $response->getBody(); // stream goes to serializer
            } else {
                $content = (string) $response->getBody();
                if ('\SpApi\Model\fulfillment\outbound\v2020_07_01\GetFulfillmentOrderResponse' !== 'string') {
                    $content = json_decode($content);
                }
            }

            return [
                ObjectSerializer::deserialize($content, '\SpApi\Model\fulfillment\outbound\v2020_07_01\GetFulfillmentOrderResponse', []),
                $response->getStatusCode(),
                $response->getHeaders(),
            ];
        } catch (ApiException $e) {
            $data = ObjectSerializer::deserialize(
                $e->getResponseBody(),
                '\SpApi\Model\fulfillment\outbound\v2020_07_01\GetFulfillmentOrderResponse',
                $e->getResponseHeaders()
            );
            $e->setResponseObject($data);

            throw $e;
        }
    }

    /**
     * Operation getFulfillmentOrderAsync.
     *
     * @param string $seller_fulfillment_order_id
     *                                            The identifier assigned to the item by the seller when the fulfillment order was created. (required)
     *
     * @throws \InvalidArgumentException
     */
    public function getFulfillmentOrderAsync(
        string $seller_fulfillment_order_id
    ): PromiseInterface {
        return $this->getFulfillmentOrderAsyncWithHttpInfo($seller_fulfillment_order_id)
            ->then(
                function ($response) {
                    return $response[0];
                }
            )
        ;
    }

    /**
     * Operation getFulfillmentOrderAsyncWithHttpInfo.
     *
     * @param string $seller_fulfillment_order_id
     *                                            The identifier assigned to the item by the seller when the fulfillment order was created. (required)
     *
     * @throws \InvalidArgumentException
     */
    public function getFulfillmentOrderAsyncWithHttpInfo(
        string $seller_fulfillment_order_id,
        ?string $restrictedDataToken = null
    ): PromiseInterface {
        $returnType = '\SpApi\Model\fulfillment\outbound\v2020_07_01\GetFulfillmentOrderResponse';
        $request = $this->getFulfillmentOrderRequest($seller_fulfillment_order_id);
        if (null !== $restrictedDataToken) {
            $request = RestrictedDataTokenSigner::sign($request, $restrictedDataToken, 'FbaOutboundApi-getFulfillmentOrder');
        } else {
            $request = $this->config->sign($request);
        }
        if ($this->rateLimiterEnabled) {
            $this->getFulfillmentOrderRateLimiter->consume()->ensureAccepted();
        }

        return $this->client
            ->sendAsync($request, $this->createHttpClientOption())
            ->then(
                function ($response) use ($returnType) {
                    if ('\SplFileObject' === $returnType) {
                        $content = $response->getBody(); // stream goes to serializer
                    } else {
                        $content = (string) $response->getBody();
                        if ('string' !== $returnType) {
                            $content = json_decode($content);
                        }
                    }

                    return [
                        ObjectSerializer::deserialize($content, $returnType, []),
                        $response->getStatusCode(),
                        $response->getHeaders(),
                    ];
                },
                function ($exception) {
                    $response = $exception->getResponse();
                    $statusCode = $response->getStatusCode();

                    throw new ApiException(
                        sprintf(
                            '[%d] Error connecting to the API (%s)',
                            $statusCode,
                            $exception->getRequest()->getUri()
                        ),
                        $statusCode,
                        $response->getHeaders(),
                        (string) $response->getBody()
                    );
                }
            )
        ;
    }

    /**
     * Create request for operation 'getFulfillmentOrder'.
     *
     * @param string $seller_fulfillment_order_id
     *                                            The identifier assigned to the item by the seller when the fulfillment order was created. (required)
     *
     * @throws \InvalidArgumentException
     */
    public function getFulfillmentOrderRequest(
        string $seller_fulfillment_order_id
    ): Request {
        // verify the required parameter 'seller_fulfillment_order_id' is set
        if (null === $seller_fulfillment_order_id || (is_array($seller_fulfillment_order_id) && 0 === count($seller_fulfillment_order_id))) {
            throw new \InvalidArgumentException(
                'Missing the required parameter $seller_fulfillment_order_id when calling getFulfillmentOrder'
            );
        }
        if (strlen($seller_fulfillment_order_id) > 40) {
            throw new \InvalidArgumentException('invalid length for "$seller_fulfillment_order_id" when calling FbaOutboundApi.getFulfillmentOrder, must be smaller than or equal to 40.');
        }

        $resourcePath = '/fba/outbound/2020-07-01/fulfillmentOrders/{sellerFulfillmentOrderId}';
        $formParams = [];
        $queryParams = [];
        $headerParams = [];
        $httpBody = '';
        $multipart = false;

        // path params
        if (null !== $seller_fulfillment_order_id) {
            $resourcePath = str_replace(
                '{sellerFulfillmentOrderId}',
                ObjectSerializer::toPathValue($seller_fulfillment_order_id),
                $resourcePath
            );
        }

        $headers = $this->headerSelector->selectHeaders(
            ['application/json', 'payload'],
            '',
            $multipart
        );

        // for model (json/xml)
        if (count($formParams) > 0) {
            if ($multipart) {
                $multipartContents = [];
                foreach ($formParams as $formParamName => $formParamValue) {
                    $formParamValueItems = is_array($formParamValue) ? $formParamValue : [$formParamValue];
                    foreach ($formParamValueItems as $formParamValueItem) {
                        $multipartContents[] = [
                            'name' => $formParamName,
                            'contents' => $formParamValueItem,
                        ];
                    }
                }
                // for HTTP post (form)
                $httpBody = new MultipartStream($multipartContents);
            } elseif ('application/json' === $headers['Content-Type']) {
                $httpBody = \GuzzleHttp\json_encode($formParams);
            } else {
                // for HTTP post (form)
                $httpBody = ObjectSerializer::buildQuery($formParams, $this->config);
            }
        }

        $defaultHeaders = [];
        if ($this->config->getUserAgent()) {
            $defaultHeaders['User-Agent'] = $this->config->getUserAgent();
        }

        $headers = array_merge(
            $defaultHeaders,
            $headerParams,
            $headers
        );

        $query = ObjectSerializer::buildQuery($queryParams, $this->config);

        return new Request(
            'GET',
            $this->config->getHost().$resourcePath.($query ? "?{$query}" : ''),
            $headers,
            $httpBody
        );
    }

    /**
     * Operation getFulfillmentPreview.
     *
     * @param GetFulfillmentPreviewRequest $body
     *                                                          GetFulfillmentPreviewRequest parameter (required)
     * @param null|string                  $restrictedDataToken Restricted Data Token (RDT) for accessing restricted resources (optional, required for operations that return PII)
     *
     * @throws ApiException              on non-2xx response
     * @throws \InvalidArgumentException
     */
    public function getFulfillmentPreview(
        GetFulfillmentPreviewRequest $body,
        ?string $restrictedDataToken = null
    ): GetFulfillmentPreviewResponse {
        list($response) = $this->getFulfillmentPreviewWithHttpInfo($body, $restrictedDataToken);

        return $response;
    }

    /**
     * Operation getFulfillmentPreviewWithHttpInfo.
     *
     * @param GetFulfillmentPreviewRequest $body
     *                                                          GetFulfillmentPreviewRequest parameter (required)
     * @param null|string                  $restrictedDataToken Restricted Data Token (RDT) for accessing restricted resources (optional, required for operations that return PII)
     *
     * @return array of \SpApi\Model\fulfillment\outbound\v2020_07_01\GetFulfillmentPreviewResponse, HTTP status code, HTTP response headers (array of strings)
     *
     * @throws ApiException              on non-2xx response
     * @throws \InvalidArgumentException
     */
    public function getFulfillmentPreviewWithHttpInfo(
        GetFulfillmentPreviewRequest $body,
        ?string $restrictedDataToken = null
    ): array {
        $request = $this->getFulfillmentPreviewRequest($body);
        if (null !== $restrictedDataToken) {
            $request = RestrictedDataTokenSigner::sign($request, $restrictedDataToken, 'FbaOutboundApi-getFulfillmentPreview');
        } else {
            $request = $this->config->sign($request);
        }

        try {
            $options = $this->createHttpClientOption();

            try {
                if ($this->rateLimiterEnabled) {
                    $this->getFulfillmentPreviewRateLimiter->consume()->ensureAccepted();
                }
                $response = $this->client->send($request, $options);
            } catch (RequestException $e) {
                throw new ApiException(
                    "[{$e->getCode()}] {$e->getResponse()->getBody()}",
                    (int) $e->getCode(),
                    $e->getResponse() ? $e->getResponse()->getHeaders() : null,
                    $e->getResponse() ? (string) $e->getResponse()->getBody() : null
                );
            } catch (ConnectException $e) {
                throw new ApiException(
                    "[{$e->getCode()}] {$e->getMessage()}",
                    (int) $e->getCode(),
                    null,
                    null
                );
            }

            $statusCode = $response->getStatusCode();

            if ($statusCode < 200 || $statusCode > 299) {
                throw new ApiException(
                    sprintf(
                        '[%d] Error connecting to the API (%s)',
                        $statusCode,
                        (string) $request->getUri()
                    ),
                    $statusCode,
                    $response->getHeaders(),
                    (string) $response->getBody()
                );
            }
            if ('\SpApi\Model\fulfillment\outbound\v2020_07_01\GetFulfillmentPreviewResponse' === '\SplFileObject') {
                $content = $response->getBody(); // stream goes to serializer
            } else {
                $content = (string) $response->getBody();
                if ('\SpApi\Model\fulfillment\outbound\v2020_07_01\GetFulfillmentPreviewResponse' !== 'string') {
                    $content = json_decode($content);
                }
            }

            return [
                ObjectSerializer::deserialize($content, '\SpApi\Model\fulfillment\outbound\v2020_07_01\GetFulfillmentPreviewResponse', []),
                $response->getStatusCode(),
                $response->getHeaders(),
            ];
        } catch (ApiException $e) {
            $data = ObjectSerializer::deserialize(
                $e->getResponseBody(),
                '\SpApi\Model\fulfillment\outbound\v2020_07_01\GetFulfillmentPreviewResponse',
                $e->getResponseHeaders()
            );
            $e->setResponseObject($data);

            throw $e;
        }
    }

    /**
     * Operation getFulfillmentPreviewAsync.
     *
     * @param GetFulfillmentPreviewRequest $body
     *                                           GetFulfillmentPreviewRequest parameter (required)
     *
     * @throws \InvalidArgumentException
     */
    public function getFulfillmentPreviewAsync(
        GetFulfillmentPreviewRequest $body
    ): PromiseInterface {
        return $this->getFulfillmentPreviewAsyncWithHttpInfo($body)
            ->then(
                function ($response) {
                    return $response[0];
                }
            )
        ;
    }

    /**
     * Operation getFulfillmentPreviewAsyncWithHttpInfo.
     *
     * @param GetFulfillmentPreviewRequest $body
     *                                           GetFulfillmentPreviewRequest parameter (required)
     *
     * @throws \InvalidArgumentException
     */
    public function getFulfillmentPreviewAsyncWithHttpInfo(
        GetFulfillmentPreviewRequest $body,
        ?string $restrictedDataToken = null
    ): PromiseInterface {
        $returnType = '\SpApi\Model\fulfillment\outbound\v2020_07_01\GetFulfillmentPreviewResponse';
        $request = $this->getFulfillmentPreviewRequest($body);
        if (null !== $restrictedDataToken) {
            $request = RestrictedDataTokenSigner::sign($request, $restrictedDataToken, 'FbaOutboundApi-getFulfillmentPreview');
        } else {
            $request = $this->config->sign($request);
        }
        if ($this->rateLimiterEnabled) {
            $this->getFulfillmentPreviewRateLimiter->consume()->ensureAccepted();
        }

        return $this->client
            ->sendAsync($request, $this->createHttpClientOption())
            ->then(
                function ($response) use ($returnType) {
                    if ('\SplFileObject' === $returnType) {
                        $content = $response->getBody(); // stream goes to serializer
                    } else {
                        $content = (string) $response->getBody();
                        if ('string' !== $returnType) {
                            $content = json_decode($content);
                        }
                    }

                    return [
                        ObjectSerializer::deserialize($content, $returnType, []),
                        $response->getStatusCode(),
                        $response->getHeaders(),
                    ];
                },
                function ($exception) {
                    $response = $exception->getResponse();
                    $statusCode = $response->getStatusCode();

                    throw new ApiException(
                        sprintf(
                            '[%d] Error connecting to the API (%s)',
                            $statusCode,
                            $exception->getRequest()->getUri()
                        ),
                        $statusCode,
                        $response->getHeaders(),
                        (string) $response->getBody()
                    );
                }
            )
        ;
    }

    /**
     * Create request for operation 'getFulfillmentPreview'.
     *
     * @param GetFulfillmentPreviewRequest $body
     *                                           GetFulfillmentPreviewRequest parameter (required)
     *
     * @throws \InvalidArgumentException
     */
    public function getFulfillmentPreviewRequest(
        GetFulfillmentPreviewRequest $body
    ): Request {
        // verify the required parameter 'body' is set
        if (null === $body || (is_array($body) && 0 === count($body))) {
            throw new \InvalidArgumentException(
                'Missing the required parameter $body when calling getFulfillmentPreview'
            );
        }

        $resourcePath = '/fba/outbound/2020-07-01/fulfillmentOrders/preview';
        $formParams = [];
        $queryParams = [];
        $headerParams = [];
        $httpBody = '';
        $multipart = false;

        $headers = $this->headerSelector->selectHeaders(
            ['application/json', 'payload'],
            'application/json',
            $multipart
        );

        // for model (json/xml)
        if (isset($body)) {
            if ('application/json' === $headers['Content-Type']) {
                $httpBody = \GuzzleHttp\json_encode(ObjectSerializer::sanitizeForSerialization($body));
            } else {
                $httpBody = $body;
            }
        } elseif (count($formParams) > 0) {
            if ($multipart) {
                $multipartContents = [];
                foreach ($formParams as $formParamName => $formParamValue) {
                    $formParamValueItems = is_array($formParamValue) ? $formParamValue : [$formParamValue];
                    foreach ($formParamValueItems as $formParamValueItem) {
                        $multipartContents[] = [
                            'name' => $formParamName,
                            'contents' => $formParamValueItem,
                        ];
                    }
                }
                // for HTTP post (form)
                $httpBody = new MultipartStream($multipartContents);
            } elseif ('application/json' === $headers['Content-Type']) {
                $httpBody = \GuzzleHttp\json_encode($formParams);
            } else {
                // for HTTP post (form)
                $httpBody = ObjectSerializer::buildQuery($formParams, $this->config);
            }
        }

        $defaultHeaders = [];
        if ($this->config->getUserAgent()) {
            $defaultHeaders['User-Agent'] = $this->config->getUserAgent();
        }

        $headers = array_merge(
            $defaultHeaders,
            $headerParams,
            $headers
        );

        $query = ObjectSerializer::buildQuery($queryParams, $this->config);

        return new Request(
            'POST',
            $this->config->getHost().$resourcePath.($query ? "?{$query}" : ''),
            $headers,
            $httpBody
        );
    }

    /**
     * Operation getPackageTrackingDetails.
     *
     * @param int         $package_number
     *                                         The unencrypted package identifier returned by the &#x60;getFulfillmentOrder&#x60; operation. (required)
     * @param null|string $restrictedDataToken Restricted Data Token (RDT) for accessing restricted resources (optional, required for operations that return PII)
     *
     * @throws ApiException              on non-2xx response
     * @throws \InvalidArgumentException
     */
    public function getPackageTrackingDetails(
        int $package_number,
        ?string $restrictedDataToken = null
    ): GetPackageTrackingDetailsResponse {
        list($response) = $this->getPackageTrackingDetailsWithHttpInfo($package_number, $restrictedDataToken);

        return $response;
    }

    /**
     * Operation getPackageTrackingDetailsWithHttpInfo.
     *
     * @param int         $package_number
     *                                         The unencrypted package identifier returned by the &#x60;getFulfillmentOrder&#x60; operation. (required)
     * @param null|string $restrictedDataToken Restricted Data Token (RDT) for accessing restricted resources (optional, required for operations that return PII)
     *
     * @return array of \SpApi\Model\fulfillment\outbound\v2020_07_01\GetPackageTrackingDetailsResponse, HTTP status code, HTTP response headers (array of strings)
     *
     * @throws ApiException              on non-2xx response
     * @throws \InvalidArgumentException
     */
    public function getPackageTrackingDetailsWithHttpInfo(
        int $package_number,
        ?string $restrictedDataToken = null
    ): array {
        $request = $this->getPackageTrackingDetailsRequest($package_number);
        if (null !== $restrictedDataToken) {
            $request = RestrictedDataTokenSigner::sign($request, $restrictedDataToken, 'FbaOutboundApi-getPackageTrackingDetails');
        } else {
            $request = $this->config->sign($request);
        }

        try {
            $options = $this->createHttpClientOption();

            try {
                if ($this->rateLimiterEnabled) {
                    $this->getPackageTrackingDetailsRateLimiter->consume()->ensureAccepted();
                }
                $response = $this->client->send($request, $options);
            } catch (RequestException $e) {
                throw new ApiException(
                    "[{$e->getCode()}] {$e->getResponse()->getBody()}",
                    (int) $e->getCode(),
                    $e->getResponse() ? $e->getResponse()->getHeaders() : null,
                    $e->getResponse() ? (string) $e->getResponse()->getBody() : null
                );
            } catch (ConnectException $e) {
                throw new ApiException(
                    "[{$e->getCode()}] {$e->getMessage()}",
                    (int) $e->getCode(),
                    null,
                    null
                );
            }

            $statusCode = $response->getStatusCode();

            if ($statusCode < 200 || $statusCode > 299) {
                throw new ApiException(
                    sprintf(
                        '[%d] Error connecting to the API (%s)',
                        $statusCode,
                        (string) $request->getUri()
                    ),
                    $statusCode,
                    $response->getHeaders(),
                    (string) $response->getBody()
                );
            }
            if ('\SpApi\Model\fulfillment\outbound\v2020_07_01\GetPackageTrackingDetailsResponse' === '\SplFileObject') {
                $content = $response->getBody(); // stream goes to serializer
            } else {
                $content = (string) $response->getBody();
                if ('\SpApi\Model\fulfillment\outbound\v2020_07_01\GetPackageTrackingDetailsResponse' !== 'string') {
                    $content = json_decode($content);
                }
            }

            return [
                ObjectSerializer::deserialize($content, '\SpApi\Model\fulfillment\outbound\v2020_07_01\GetPackageTrackingDetailsResponse', []),
                $response->getStatusCode(),
                $response->getHeaders(),
            ];
        } catch (ApiException $e) {
            $data = ObjectSerializer::deserialize(
                $e->getResponseBody(),
                '\SpApi\Model\fulfillment\outbound\v2020_07_01\GetPackageTrackingDetailsResponse',
                $e->getResponseHeaders()
            );
            $e->setResponseObject($data);

            throw $e;
        }
    }

    /**
     * Operation getPackageTrackingDetailsAsync.
     *
     * @param int $package_number
     *                            The unencrypted package identifier returned by the &#x60;getFulfillmentOrder&#x60; operation. (required)
     *
     * @throws \InvalidArgumentException
     */
    public function getPackageTrackingDetailsAsync(
        int $package_number
    ): PromiseInterface {
        return $this->getPackageTrackingDetailsAsyncWithHttpInfo($package_number)
            ->then(
                function ($response) {
                    return $response[0];
                }
            )
        ;
    }

    /**
     * Operation getPackageTrackingDetailsAsyncWithHttpInfo.
     *
     * @param int $package_number
     *                            The unencrypted package identifier returned by the &#x60;getFulfillmentOrder&#x60; operation. (required)
     *
     * @throws \InvalidArgumentException
     */
    public function getPackageTrackingDetailsAsyncWithHttpInfo(
        int $package_number,
        ?string $restrictedDataToken = null
    ): PromiseInterface {
        $returnType = '\SpApi\Model\fulfillment\outbound\v2020_07_01\GetPackageTrackingDetailsResponse';
        $request = $this->getPackageTrackingDetailsRequest($package_number);
        if (null !== $restrictedDataToken) {
            $request = RestrictedDataTokenSigner::sign($request, $restrictedDataToken, 'FbaOutboundApi-getPackageTrackingDetails');
        } else {
            $request = $this->config->sign($request);
        }
        if ($this->rateLimiterEnabled) {
            $this->getPackageTrackingDetailsRateLimiter->consume()->ensureAccepted();
        }

        return $this->client
            ->sendAsync($request, $this->createHttpClientOption())
            ->then(
                function ($response) use ($returnType) {
                    if ('\SplFileObject' === $returnType) {
                        $content = $response->getBody(); // stream goes to serializer
                    } else {
                        $content = (string) $response->getBody();
                        if ('string' !== $returnType) {
                            $content = json_decode($content);
                        }
                    }

                    return [
                        ObjectSerializer::deserialize($content, $returnType, []),
                        $response->getStatusCode(),
                        $response->getHeaders(),
                    ];
                },
                function ($exception) {
                    $response = $exception->getResponse();
                    $statusCode = $response->getStatusCode();

                    throw new ApiException(
                        sprintf(
                            '[%d] Error connecting to the API (%s)',
                            $statusCode,
                            $exception->getRequest()->getUri()
                        ),
                        $statusCode,
                        $response->getHeaders(),
                        (string) $response->getBody()
                    );
                }
            )
        ;
    }

    /**
     * Create request for operation 'getPackageTrackingDetails'.
     *
     * @param int $package_number
     *                            The unencrypted package identifier returned by the &#x60;getFulfillmentOrder&#x60; operation. (required)
     *
     * @throws \InvalidArgumentException
     */
    public function getPackageTrackingDetailsRequest(
        int $package_number
    ): Request {
        // verify the required parameter 'package_number' is set
        if (null === $package_number || (is_array($package_number) && 0 === count($package_number))) {
            throw new \InvalidArgumentException(
                'Missing the required parameter $package_number when calling getPackageTrackingDetails'
            );
        }

        $resourcePath = '/fba/outbound/2020-07-01/tracking';
        $formParams = [];
        $queryParams = [];
        $headerParams = [];
        $httpBody = '';
        $multipart = false;

        // query params
        $queryParams = array_merge($queryParams, ObjectSerializer::toQueryValue(
            $package_number,
            'packageNumber', // param base name
            'integer', // openApiType
            '', // style
            false, // explode
            true, // required
            $this->config
        ) ?? []);

        $headers = $this->headerSelector->selectHeaders(
            ['application/json', 'payload'],
            '',
            $multipart
        );

        // for model (json/xml)
        if (count($formParams) > 0) {
            if ($multipart) {
                $multipartContents = [];
                foreach ($formParams as $formParamName => $formParamValue) {
                    $formParamValueItems = is_array($formParamValue) ? $formParamValue : [$formParamValue];
                    foreach ($formParamValueItems as $formParamValueItem) {
                        $multipartContents[] = [
                            'name' => $formParamName,
                            'contents' => $formParamValueItem,
                        ];
                    }
                }
                // for HTTP post (form)
                $httpBody = new MultipartStream($multipartContents);
            } elseif ('application/json' === $headers['Content-Type']) {
                $httpBody = \GuzzleHttp\json_encode($formParams);
            } else {
                // for HTTP post (form)
                $httpBody = ObjectSerializer::buildQuery($formParams, $this->config);
            }
        }

        $defaultHeaders = [];
        if ($this->config->getUserAgent()) {
            $defaultHeaders['User-Agent'] = $this->config->getUserAgent();
        }

        $headers = array_merge(
            $defaultHeaders,
            $headerParams,
            $headers
        );

        $query = ObjectSerializer::buildQuery($queryParams, $this->config);

        return new Request(
            'GET',
            $this->config->getHost().$resourcePath.($query ? "?{$query}" : ''),
            $headers,
            $httpBody
        );
    }

    /**
     * Operation listAllFulfillmentOrders.
     *
     * @param null|\DateTime $query_start_date
     *                                            A date used to select fulfillment orders that were last updated after (or at) a specified time. An update is defined as any change in fulfillment order status, including the creation of a new fulfillment order. (optional)
     * @param null|string    $next_token
     *                                            A string token returned in the response to your previous request. (optional)
     * @param null|string    $restrictedDataToken Restricted Data Token (RDT) for accessing restricted resources (optional, required for operations that return PII)
     *
     * @throws ApiException              on non-2xx response
     * @throws \InvalidArgumentException
     */
    public function listAllFulfillmentOrders(
        ?\DateTime $query_start_date = null,
        ?string $next_token = null,
        ?string $restrictedDataToken = null
    ): ListAllFulfillmentOrdersResponse {
        list($response) = $this->listAllFulfillmentOrdersWithHttpInfo($query_start_date, $next_token, $restrictedDataToken);

        return $response;
    }

    /**
     * Operation listAllFulfillmentOrdersWithHttpInfo.
     *
     * @param null|\DateTime $query_start_date
     *                                            A date used to select fulfillment orders that were last updated after (or at) a specified time. An update is defined as any change in fulfillment order status, including the creation of a new fulfillment order. (optional)
     * @param null|string    $next_token
     *                                            A string token returned in the response to your previous request. (optional)
     * @param null|string    $restrictedDataToken Restricted Data Token (RDT) for accessing restricted resources (optional, required for operations that return PII)
     *
     * @return array of \SpApi\Model\fulfillment\outbound\v2020_07_01\ListAllFulfillmentOrdersResponse, HTTP status code, HTTP response headers (array of strings)
     *
     * @throws ApiException              on non-2xx response
     * @throws \InvalidArgumentException
     */
    public function listAllFulfillmentOrdersWithHttpInfo(
        ?\DateTime $query_start_date = null,
        ?string $next_token = null,
        ?string $restrictedDataToken = null
    ): array {
        $request = $this->listAllFulfillmentOrdersRequest($query_start_date, $next_token);
        if (null !== $restrictedDataToken) {
            $request = RestrictedDataTokenSigner::sign($request, $restrictedDataToken, 'FbaOutboundApi-listAllFulfillmentOrders');
        } else {
            $request = $this->config->sign($request);
        }

        try {
            $options = $this->createHttpClientOption();

            try {
                if ($this->rateLimiterEnabled) {
                    $this->listAllFulfillmentOrdersRateLimiter->consume()->ensureAccepted();
                }
                $response = $this->client->send($request, $options);
            } catch (RequestException $e) {
                throw new ApiException(
                    "[{$e->getCode()}] {$e->getResponse()->getBody()}",
                    (int) $e->getCode(),
                    $e->getResponse() ? $e->getResponse()->getHeaders() : null,
                    $e->getResponse() ? (string) $e->getResponse()->getBody() : null
                );
            } catch (ConnectException $e) {
                throw new ApiException(
                    "[{$e->getCode()}] {$e->getMessage()}",
                    (int) $e->getCode(),
                    null,
                    null
                );
            }

            $statusCode = $response->getStatusCode();

            if ($statusCode < 200 || $statusCode > 299) {
                throw new ApiException(
                    sprintf(
                        '[%d] Error connecting to the API (%s)',
                        $statusCode,
                        (string) $request->getUri()
                    ),
                    $statusCode,
                    $response->getHeaders(),
                    (string) $response->getBody()
                );
            }
            if ('\SpApi\Model\fulfillment\outbound\v2020_07_01\ListAllFulfillmentOrdersResponse' === '\SplFileObject') {
                $content = $response->getBody(); // stream goes to serializer
            } else {
                $content = (string) $response->getBody();
                if ('\SpApi\Model\fulfillment\outbound\v2020_07_01\ListAllFulfillmentOrdersResponse' !== 'string') {
                    $content = json_decode($content);
                }
            }

            return [
                ObjectSerializer::deserialize($content, '\SpApi\Model\fulfillment\outbound\v2020_07_01\ListAllFulfillmentOrdersResponse', []),
                $response->getStatusCode(),
                $response->getHeaders(),
            ];
        } catch (ApiException $e) {
            $data = ObjectSerializer::deserialize(
                $e->getResponseBody(),
                '\SpApi\Model\fulfillment\outbound\v2020_07_01\ListAllFulfillmentOrdersResponse',
                $e->getResponseHeaders()
            );
            $e->setResponseObject($data);

            throw $e;
        }
    }

    /**
     * Operation listAllFulfillmentOrdersAsync.
     *
     * @param null|\DateTime $query_start_date
     *                                         A date used to select fulfillment orders that were last updated after (or at) a specified time. An update is defined as any change in fulfillment order status, including the creation of a new fulfillment order. (optional)
     * @param null|string    $next_token
     *                                         A string token returned in the response to your previous request. (optional)
     *
     * @throws \InvalidArgumentException
     */
    public function listAllFulfillmentOrdersAsync(
        ?\DateTime $query_start_date = null,
        ?string $next_token = null
    ): PromiseInterface {
        return $this->listAllFulfillmentOrdersAsyncWithHttpInfo($query_start_date, $next_token)
            ->then(
                function ($response) {
                    return $response[0];
                }
            )
        ;
    }

    /**
     * Operation listAllFulfillmentOrdersAsyncWithHttpInfo.
     *
     * @param null|\DateTime $query_start_date
     *                                         A date used to select fulfillment orders that were last updated after (or at) a specified time. An update is defined as any change in fulfillment order status, including the creation of a new fulfillment order. (optional)
     * @param null|string    $next_token
     *                                         A string token returned in the response to your previous request. (optional)
     *
     * @throws \InvalidArgumentException
     */
    public function listAllFulfillmentOrdersAsyncWithHttpInfo(
        ?\DateTime $query_start_date = null,
        ?string $next_token = null,
        ?string $restrictedDataToken = null
    ): PromiseInterface {
        $returnType = '\SpApi\Model\fulfillment\outbound\v2020_07_01\ListAllFulfillmentOrdersResponse';
        $request = $this->listAllFulfillmentOrdersRequest($query_start_date, $next_token);
        if (null !== $restrictedDataToken) {
            $request = RestrictedDataTokenSigner::sign($request, $restrictedDataToken, 'FbaOutboundApi-listAllFulfillmentOrders');
        } else {
            $request = $this->config->sign($request);
        }
        if ($this->rateLimiterEnabled) {
            $this->listAllFulfillmentOrdersRateLimiter->consume()->ensureAccepted();
        }

        return $this->client
            ->sendAsync($request, $this->createHttpClientOption())
            ->then(
                function ($response) use ($returnType) {
                    if ('\SplFileObject' === $returnType) {
                        $content = $response->getBody(); // stream goes to serializer
                    } else {
                        $content = (string) $response->getBody();
                        if ('string' !== $returnType) {
                            $content = json_decode($content);
                        }
                    }

                    return [
                        ObjectSerializer::deserialize($content, $returnType, []),
                        $response->getStatusCode(),
                        $response->getHeaders(),
                    ];
                },
                function ($exception) {
                    $response = $exception->getResponse();
                    $statusCode = $response->getStatusCode();

                    throw new ApiException(
                        sprintf(
                            '[%d] Error connecting to the API (%s)',
                            $statusCode,
                            $exception->getRequest()->getUri()
                        ),
                        $statusCode,
                        $response->getHeaders(),
                        (string) $response->getBody()
                    );
                }
            )
        ;
    }

    /**
     * Create request for operation 'listAllFulfillmentOrders'.
     *
     * @param null|\DateTime $query_start_date
     *                                         A date used to select fulfillment orders that were last updated after (or at) a specified time. An update is defined as any change in fulfillment order status, including the creation of a new fulfillment order. (optional)
     * @param null|string    $next_token
     *                                         A string token returned in the response to your previous request. (optional)
     *
     * @throws \InvalidArgumentException
     */
    public function listAllFulfillmentOrdersRequest(
        ?\DateTime $query_start_date = null,
        ?string $next_token = null
    ): Request {
        $resourcePath = '/fba/outbound/2020-07-01/fulfillmentOrders';
        $formParams = [];
        $queryParams = [];
        $headerParams = [];
        $httpBody = '';
        $multipart = false;

        // query params
        $queryParams = array_merge($queryParams, ObjectSerializer::toQueryValue(
            $query_start_date,
            'queryStartDate', // param base name
            'string', // openApiType
            '', // style
            false, // explode
            false, // required
            $this->config
        ) ?? []);
        // query params
        $queryParams = array_merge($queryParams, ObjectSerializer::toQueryValue(
            $next_token,
            'nextToken', // param base name
            'string', // openApiType
            '', // style
            false, // explode
            false, // required
            $this->config
        ) ?? []);

        $headers = $this->headerSelector->selectHeaders(
            ['application/json', 'payload'],
            '',
            $multipart
        );

        // for model (json/xml)
        if (count($formParams) > 0) {
            if ($multipart) {
                $multipartContents = [];
                foreach ($formParams as $formParamName => $formParamValue) {
                    $formParamValueItems = is_array($formParamValue) ? $formParamValue : [$formParamValue];
                    foreach ($formParamValueItems as $formParamValueItem) {
                        $multipartContents[] = [
                            'name' => $formParamName,
                            'contents' => $formParamValueItem,
                        ];
                    }
                }
                // for HTTP post (form)
                $httpBody = new MultipartStream($multipartContents);
            } elseif ('application/json' === $headers['Content-Type']) {
                $httpBody = \GuzzleHttp\json_encode($formParams);
            } else {
                // for HTTP post (form)
                $httpBody = ObjectSerializer::buildQuery($formParams, $this->config);
            }
        }

        $defaultHeaders = [];
        if ($this->config->getUserAgent()) {
            $defaultHeaders['User-Agent'] = $this->config->getUserAgent();
        }

        $headers = array_merge(
            $defaultHeaders,
            $headerParams,
            $headers
        );

        $query = ObjectSerializer::buildQuery($queryParams, $this->config);

        return new Request(
            'GET',
            $this->config->getHost().$resourcePath.($query ? "?{$query}" : ''),
            $headers,
            $httpBody
        );
    }

    /**
     * Operation listReturnReasonCodes.
     *
     * @param string      $seller_sku
     *                                                 The seller SKU for which return reason codes are required. (required)
     * @param null|string $marketplace_id
     *                                                 The marketplace for which the seller wants return reason codes. (optional)
     * @param null|string $seller_fulfillment_order_id
     *                                                 The identifier assigned to the item by the seller when the fulfillment order was created. The service uses this value to determine the marketplace for which the seller wants return reason codes. (optional)
     * @param null|string $language
     *                                                 The language that the &#x60;TranslatedDescription&#x60; property of the &#x60;ReasonCodeDetails&#x60; response object should be translated into. (optional)
     * @param null|string $restrictedDataToken         Restricted Data Token (RDT) for accessing restricted resources (optional, required for operations that return PII)
     *
     * @throws ApiException              on non-2xx response
     * @throws \InvalidArgumentException
     */
    public function listReturnReasonCodes(
        string $seller_sku,
        ?string $marketplace_id = null,
        ?string $seller_fulfillment_order_id = null,
        ?string $language = null,
        ?string $restrictedDataToken = null
    ): ListReturnReasonCodesResponse {
        list($response) = $this->listReturnReasonCodesWithHttpInfo($seller_sku, $marketplace_id, $seller_fulfillment_order_id, $language, $restrictedDataToken);

        return $response;
    }

    /**
     * Operation listReturnReasonCodesWithHttpInfo.
     *
     * @param string      $seller_sku
     *                                                 The seller SKU for which return reason codes are required. (required)
     * @param null|string $marketplace_id
     *                                                 The marketplace for which the seller wants return reason codes. (optional)
     * @param null|string $seller_fulfillment_order_id
     *                                                 The identifier assigned to the item by the seller when the fulfillment order was created. The service uses this value to determine the marketplace for which the seller wants return reason codes. (optional)
     * @param null|string $language
     *                                                 The language that the &#x60;TranslatedDescription&#x60; property of the &#x60;ReasonCodeDetails&#x60; response object should be translated into. (optional)
     * @param null|string $restrictedDataToken         Restricted Data Token (RDT) for accessing restricted resources (optional, required for operations that return PII)
     *
     * @return array of \SpApi\Model\fulfillment\outbound\v2020_07_01\ListReturnReasonCodesResponse, HTTP status code, HTTP response headers (array of strings)
     *
     * @throws ApiException              on non-2xx response
     * @throws \InvalidArgumentException
     */
    public function listReturnReasonCodesWithHttpInfo(
        string $seller_sku,
        ?string $marketplace_id = null,
        ?string $seller_fulfillment_order_id = null,
        ?string $language = null,
        ?string $restrictedDataToken = null
    ): array {
        $request = $this->listReturnReasonCodesRequest($seller_sku, $marketplace_id, $seller_fulfillment_order_id, $language);
        if (null !== $restrictedDataToken) {
            $request = RestrictedDataTokenSigner::sign($request, $restrictedDataToken, 'FbaOutboundApi-listReturnReasonCodes');
        } else {
            $request = $this->config->sign($request);
        }

        try {
            $options = $this->createHttpClientOption();

            try {
                if ($this->rateLimiterEnabled) {
                    $this->listReturnReasonCodesRateLimiter->consume()->ensureAccepted();
                }
                $response = $this->client->send($request, $options);
            } catch (RequestException $e) {
                throw new ApiException(
                    "[{$e->getCode()}] {$e->getResponse()->getBody()}",
                    (int) $e->getCode(),
                    $e->getResponse() ? $e->getResponse()->getHeaders() : null,
                    $e->getResponse() ? (string) $e->getResponse()->getBody() : null
                );
            } catch (ConnectException $e) {
                throw new ApiException(
                    "[{$e->getCode()}] {$e->getMessage()}",
                    (int) $e->getCode(),
                    null,
                    null
                );
            }

            $statusCode = $response->getStatusCode();

            if ($statusCode < 200 || $statusCode > 299) {
                throw new ApiException(
                    sprintf(
                        '[%d] Error connecting to the API (%s)',
                        $statusCode,
                        (string) $request->getUri()
                    ),
                    $statusCode,
                    $response->getHeaders(),
                    (string) $response->getBody()
                );
            }
            if ('\SpApi\Model\fulfillment\outbound\v2020_07_01\ListReturnReasonCodesResponse' === '\SplFileObject') {
                $content = $response->getBody(); // stream goes to serializer
            } else {
                $content = (string) $response->getBody();
                if ('\SpApi\Model\fulfillment\outbound\v2020_07_01\ListReturnReasonCodesResponse' !== 'string') {
                    $content = json_decode($content);
                }
            }

            return [
                ObjectSerializer::deserialize($content, '\SpApi\Model\fulfillment\outbound\v2020_07_01\ListReturnReasonCodesResponse', []),
                $response->getStatusCode(),
                $response->getHeaders(),
            ];
        } catch (ApiException $e) {
            $data = ObjectSerializer::deserialize(
                $e->getResponseBody(),
                '\SpApi\Model\fulfillment\outbound\v2020_07_01\ListReturnReasonCodesResponse',
                $e->getResponseHeaders()
            );
            $e->setResponseObject($data);

            throw $e;
        }
    }

    /**
     * Operation listReturnReasonCodesAsync.
     *
     * @param string      $seller_sku
     *                                                 The seller SKU for which return reason codes are required. (required)
     * @param null|string $marketplace_id
     *                                                 The marketplace for which the seller wants return reason codes. (optional)
     * @param null|string $seller_fulfillment_order_id
     *                                                 The identifier assigned to the item by the seller when the fulfillment order was created. The service uses this value to determine the marketplace for which the seller wants return reason codes. (optional)
     * @param null|string $language
     *                                                 The language that the &#x60;TranslatedDescription&#x60; property of the &#x60;ReasonCodeDetails&#x60; response object should be translated into. (optional)
     *
     * @throws \InvalidArgumentException
     */
    public function listReturnReasonCodesAsync(
        string $seller_sku,
        ?string $marketplace_id = null,
        ?string $seller_fulfillment_order_id = null,
        ?string $language = null
    ): PromiseInterface {
        return $this->listReturnReasonCodesAsyncWithHttpInfo($seller_sku, $marketplace_id, $seller_fulfillment_order_id, $language)
            ->then(
                function ($response) {
                    return $response[0];
                }
            )
        ;
    }

    /**
     * Operation listReturnReasonCodesAsyncWithHttpInfo.
     *
     * @param string      $seller_sku
     *                                                 The seller SKU for which return reason codes are required. (required)
     * @param null|string $marketplace_id
     *                                                 The marketplace for which the seller wants return reason codes. (optional)
     * @param null|string $seller_fulfillment_order_id
     *                                                 The identifier assigned to the item by the seller when the fulfillment order was created. The service uses this value to determine the marketplace for which the seller wants return reason codes. (optional)
     * @param null|string $language
     *                                                 The language that the &#x60;TranslatedDescription&#x60; property of the &#x60;ReasonCodeDetails&#x60; response object should be translated into. (optional)
     *
     * @throws \InvalidArgumentException
     */
    public function listReturnReasonCodesAsyncWithHttpInfo(
        string $seller_sku,
        ?string $marketplace_id = null,
        ?string $seller_fulfillment_order_id = null,
        ?string $language = null,
        ?string $restrictedDataToken = null
    ): PromiseInterface {
        $returnType = '\SpApi\Model\fulfillment\outbound\v2020_07_01\ListReturnReasonCodesResponse';
        $request = $this->listReturnReasonCodesRequest($seller_sku, $marketplace_id, $seller_fulfillment_order_id, $language);
        if (null !== $restrictedDataToken) {
            $request = RestrictedDataTokenSigner::sign($request, $restrictedDataToken, 'FbaOutboundApi-listReturnReasonCodes');
        } else {
            $request = $this->config->sign($request);
        }
        if ($this->rateLimiterEnabled) {
            $this->listReturnReasonCodesRateLimiter->consume()->ensureAccepted();
        }

        return $this->client
            ->sendAsync($request, $this->createHttpClientOption())
            ->then(
                function ($response) use ($returnType) {
                    if ('\SplFileObject' === $returnType) {
                        $content = $response->getBody(); // stream goes to serializer
                    } else {
                        $content = (string) $response->getBody();
                        if ('string' !== $returnType) {
                            $content = json_decode($content);
                        }
                    }

                    return [
                        ObjectSerializer::deserialize($content, $returnType, []),
                        $response->getStatusCode(),
                        $response->getHeaders(),
                    ];
                },
                function ($exception) {
                    $response = $exception->getResponse();
                    $statusCode = $response->getStatusCode();

                    throw new ApiException(
                        sprintf(
                            '[%d] Error connecting to the API (%s)',
                            $statusCode,
                            $exception->getRequest()->getUri()
                        ),
                        $statusCode,
                        $response->getHeaders(),
                        (string) $response->getBody()
                    );
                }
            )
        ;
    }

    /**
     * Create request for operation 'listReturnReasonCodes'.
     *
     * @param string      $seller_sku
     *                                                 The seller SKU for which return reason codes are required. (required)
     * @param null|string $marketplace_id
     *                                                 The marketplace for which the seller wants return reason codes. (optional)
     * @param null|string $seller_fulfillment_order_id
     *                                                 The identifier assigned to the item by the seller when the fulfillment order was created. The service uses this value to determine the marketplace for which the seller wants return reason codes. (optional)
     * @param null|string $language
     *                                                 The language that the &#x60;TranslatedDescription&#x60; property of the &#x60;ReasonCodeDetails&#x60; response object should be translated into. (optional)
     *
     * @throws \InvalidArgumentException
     */
    public function listReturnReasonCodesRequest(
        string $seller_sku,
        ?string $marketplace_id = null,
        ?string $seller_fulfillment_order_id = null,
        ?string $language = null
    ): Request {
        // verify the required parameter 'seller_sku' is set
        if (null === $seller_sku || (is_array($seller_sku) && 0 === count($seller_sku))) {
            throw new \InvalidArgumentException(
                'Missing the required parameter $seller_sku when calling listReturnReasonCodes'
            );
        }

        $resourcePath = '/fba/outbound/2020-07-01/returnReasonCodes';
        $formParams = [];
        $queryParams = [];
        $headerParams = [];
        $httpBody = '';
        $multipart = false;

        // query params
        $queryParams = array_merge($queryParams, ObjectSerializer::toQueryValue(
            $seller_sku,
            'sellerSku', // param base name
            'string', // openApiType
            '', // style
            false, // explode
            true, // required
            $this->config
        ) ?? []);
        // query params
        $queryParams = array_merge($queryParams, ObjectSerializer::toQueryValue(
            $marketplace_id,
            'marketplaceId', // param base name
            'string', // openApiType
            '', // style
            false, // explode
            false, // required
            $this->config
        ) ?? []);
        // query params
        $queryParams = array_merge($queryParams, ObjectSerializer::toQueryValue(
            $seller_fulfillment_order_id,
            'sellerFulfillmentOrderId', // param base name
            'string', // openApiType
            '', // style
            false, // explode
            false, // required
            $this->config
        ) ?? []);
        // query params
        $queryParams = array_merge($queryParams, ObjectSerializer::toQueryValue(
            $language,
            'language', // param base name
            'string', // openApiType
            '', // style
            false, // explode
            false, // required
            $this->config
        ) ?? []);

        $headers = $this->headerSelector->selectHeaders(
            ['application/json', 'payload'],
            '',
            $multipart
        );

        // for model (json/xml)
        if (count($formParams) > 0) {
            if ($multipart) {
                $multipartContents = [];
                foreach ($formParams as $formParamName => $formParamValue) {
                    $formParamValueItems = is_array($formParamValue) ? $formParamValue : [$formParamValue];
                    foreach ($formParamValueItems as $formParamValueItem) {
                        $multipartContents[] = [
                            'name' => $formParamName,
                            'contents' => $formParamValueItem,
                        ];
                    }
                }
                // for HTTP post (form)
                $httpBody = new MultipartStream($multipartContents);
            } elseif ('application/json' === $headers['Content-Type']) {
                $httpBody = \GuzzleHttp\json_encode($formParams);
            } else {
                // for HTTP post (form)
                $httpBody = ObjectSerializer::buildQuery($formParams, $this->config);
            }
        }

        $defaultHeaders = [];
        if ($this->config->getUserAgent()) {
            $defaultHeaders['User-Agent'] = $this->config->getUserAgent();
        }

        $headers = array_merge(
            $defaultHeaders,
            $headerParams,
            $headers
        );

        $query = ObjectSerializer::buildQuery($queryParams, $this->config);

        return new Request(
            'GET',
            $this->config->getHost().$resourcePath.($query ? "?{$query}" : ''),
            $headers,
            $httpBody
        );
    }

    /**
     * Operation submitFulfillmentOrderStatusUpdate.
     *
     * @param string                                    $seller_fulfillment_order_id
     *                                                                               The identifier assigned to the item by the seller when the fulfillment order was created. (required)
     * @param SubmitFulfillmentOrderStatusUpdateRequest $body
     *                                                                               The identifier assigned to the item by the seller when the fulfillment order was created. (required)
     * @param null|string                               $restrictedDataToken         Restricted Data Token (RDT) for accessing restricted resources (optional, required for operations that return PII)
     *
     * @throws ApiException              on non-2xx response
     * @throws \InvalidArgumentException
     */
    public function submitFulfillmentOrderStatusUpdate(
        string $seller_fulfillment_order_id,
        SubmitFulfillmentOrderStatusUpdateRequest $body,
        ?string $restrictedDataToken = null
    ): SubmitFulfillmentOrderStatusUpdateResponse {
        list($response) = $this->submitFulfillmentOrderStatusUpdateWithHttpInfo($seller_fulfillment_order_id, $body, $restrictedDataToken);

        return $response;
    }

    /**
     * Operation submitFulfillmentOrderStatusUpdateWithHttpInfo.
     *
     * @param string                                    $seller_fulfillment_order_id
     *                                                                               The identifier assigned to the item by the seller when the fulfillment order was created. (required)
     * @param SubmitFulfillmentOrderStatusUpdateRequest $body
     *                                                                               The identifier assigned to the item by the seller when the fulfillment order was created. (required)
     * @param null|string                               $restrictedDataToken         Restricted Data Token (RDT) for accessing restricted resources (optional, required for operations that return PII)
     *
     * @return array of \SpApi\Model\fulfillment\outbound\v2020_07_01\SubmitFulfillmentOrderStatusUpdateResponse, HTTP status code, HTTP response headers (array of strings)
     *
     * @throws ApiException              on non-2xx response
     * @throws \InvalidArgumentException
     */
    public function submitFulfillmentOrderStatusUpdateWithHttpInfo(
        string $seller_fulfillment_order_id,
        SubmitFulfillmentOrderStatusUpdateRequest $body,
        ?string $restrictedDataToken = null
    ): array {
        $request = $this->submitFulfillmentOrderStatusUpdateRequest($seller_fulfillment_order_id, $body);
        if (null !== $restrictedDataToken) {
            $request = RestrictedDataTokenSigner::sign($request, $restrictedDataToken, 'FbaOutboundApi-submitFulfillmentOrderStatusUpdate');
        } else {
            $request = $this->config->sign($request);
        }

        try {
            $options = $this->createHttpClientOption();

            try {
                if ($this->rateLimiterEnabled) {
                    $this->submitFulfillmentOrderStatusUpdateRateLimiter->consume()->ensureAccepted();
                }
                $response = $this->client->send($request, $options);
            } catch (RequestException $e) {
                throw new ApiException(
                    "[{$e->getCode()}] {$e->getResponse()->getBody()}",
                    (int) $e->getCode(),
                    $e->getResponse() ? $e->getResponse()->getHeaders() : null,
                    $e->getResponse() ? (string) $e->getResponse()->getBody() : null
                );
            } catch (ConnectException $e) {
                throw new ApiException(
                    "[{$e->getCode()}] {$e->getMessage()}",
                    (int) $e->getCode(),
                    null,
                    null
                );
            }

            $statusCode = $response->getStatusCode();

            if ($statusCode < 200 || $statusCode > 299) {
                throw new ApiException(
                    sprintf(
                        '[%d] Error connecting to the API (%s)',
                        $statusCode,
                        (string) $request->getUri()
                    ),
                    $statusCode,
                    $response->getHeaders(),
                    (string) $response->getBody()
                );
            }
            if ('\SpApi\Model\fulfillment\outbound\v2020_07_01\SubmitFulfillmentOrderStatusUpdateResponse' === '\SplFileObject') {
                $content = $response->getBody(); // stream goes to serializer
            } else {
                $content = (string) $response->getBody();
                if ('\SpApi\Model\fulfillment\outbound\v2020_07_01\SubmitFulfillmentOrderStatusUpdateResponse' !== 'string') {
                    $content = json_decode($content);
                }
            }

            return [
                ObjectSerializer::deserialize($content, '\SpApi\Model\fulfillment\outbound\v2020_07_01\SubmitFulfillmentOrderStatusUpdateResponse', []),
                $response->getStatusCode(),
                $response->getHeaders(),
            ];
        } catch (ApiException $e) {
            $data = ObjectSerializer::deserialize(
                $e->getResponseBody(),
                '\SpApi\Model\fulfillment\outbound\v2020_07_01\SubmitFulfillmentOrderStatusUpdateResponse',
                $e->getResponseHeaders()
            );
            $e->setResponseObject($data);

            throw $e;
        }
    }

    /**
     * Operation submitFulfillmentOrderStatusUpdateAsync.
     *
     * @param string                                    $seller_fulfillment_order_id
     *                                                                               The identifier assigned to the item by the seller when the fulfillment order was created. (required)
     * @param SubmitFulfillmentOrderStatusUpdateRequest $body
     *                                                                               The identifier assigned to the item by the seller when the fulfillment order was created. (required)
     *
     * @throws \InvalidArgumentException
     */
    public function submitFulfillmentOrderStatusUpdateAsync(
        string $seller_fulfillment_order_id,
        SubmitFulfillmentOrderStatusUpdateRequest $body
    ): PromiseInterface {
        return $this->submitFulfillmentOrderStatusUpdateAsyncWithHttpInfo($seller_fulfillment_order_id, $body)
            ->then(
                function ($response) {
                    return $response[0];
                }
            )
        ;
    }

    /**
     * Operation submitFulfillmentOrderStatusUpdateAsyncWithHttpInfo.
     *
     * @param string                                    $seller_fulfillment_order_id
     *                                                                               The identifier assigned to the item by the seller when the fulfillment order was created. (required)
     * @param SubmitFulfillmentOrderStatusUpdateRequest $body
     *                                                                               The identifier assigned to the item by the seller when the fulfillment order was created. (required)
     *
     * @throws \InvalidArgumentException
     */
    public function submitFulfillmentOrderStatusUpdateAsyncWithHttpInfo(
        string $seller_fulfillment_order_id,
        SubmitFulfillmentOrderStatusUpdateRequest $body,
        ?string $restrictedDataToken = null
    ): PromiseInterface {
        $returnType = '\SpApi\Model\fulfillment\outbound\v2020_07_01\SubmitFulfillmentOrderStatusUpdateResponse';
        $request = $this->submitFulfillmentOrderStatusUpdateRequest($seller_fulfillment_order_id, $body);
        if (null !== $restrictedDataToken) {
            $request = RestrictedDataTokenSigner::sign($request, $restrictedDataToken, 'FbaOutboundApi-submitFulfillmentOrderStatusUpdate');
        } else {
            $request = $this->config->sign($request);
        }
        if ($this->rateLimiterEnabled) {
            $this->submitFulfillmentOrderStatusUpdateRateLimiter->consume()->ensureAccepted();
        }

        return $this->client
            ->sendAsync($request, $this->createHttpClientOption())
            ->then(
                function ($response) use ($returnType) {
                    if ('\SplFileObject' === $returnType) {
                        $content = $response->getBody(); // stream goes to serializer
                    } else {
                        $content = (string) $response->getBody();
                        if ('string' !== $returnType) {
                            $content = json_decode($content);
                        }
                    }

                    return [
                        ObjectSerializer::deserialize($content, $returnType, []),
                        $response->getStatusCode(),
                        $response->getHeaders(),
                    ];
                },
                function ($exception) {
                    $response = $exception->getResponse();
                    $statusCode = $response->getStatusCode();

                    throw new ApiException(
                        sprintf(
                            '[%d] Error connecting to the API (%s)',
                            $statusCode,
                            $exception->getRequest()->getUri()
                        ),
                        $statusCode,
                        $response->getHeaders(),
                        (string) $response->getBody()
                    );
                }
            )
        ;
    }

    /**
     * Create request for operation 'submitFulfillmentOrderStatusUpdate'.
     *
     * @param string                                    $seller_fulfillment_order_id
     *                                                                               The identifier assigned to the item by the seller when the fulfillment order was created. (required)
     * @param SubmitFulfillmentOrderStatusUpdateRequest $body
     *                                                                               The identifier assigned to the item by the seller when the fulfillment order was created. (required)
     *
     * @throws \InvalidArgumentException
     */
    public function submitFulfillmentOrderStatusUpdateRequest(
        string $seller_fulfillment_order_id,
        SubmitFulfillmentOrderStatusUpdateRequest $body
    ): Request {
        // verify the required parameter 'seller_fulfillment_order_id' is set
        if (null === $seller_fulfillment_order_id || (is_array($seller_fulfillment_order_id) && 0 === count($seller_fulfillment_order_id))) {
            throw new \InvalidArgumentException(
                'Missing the required parameter $seller_fulfillment_order_id when calling submitFulfillmentOrderStatusUpdate'
            );
        }
        if (strlen($seller_fulfillment_order_id) > 40) {
            throw new \InvalidArgumentException('invalid length for "$seller_fulfillment_order_id" when calling FbaOutboundApi.submitFulfillmentOrderStatusUpdate, must be smaller than or equal to 40.');
        }

        // verify the required parameter 'body' is set
        if (null === $body || (is_array($body) && 0 === count($body))) {
            throw new \InvalidArgumentException(
                'Missing the required parameter $body when calling submitFulfillmentOrderStatusUpdate'
            );
        }

        $resourcePath = '/fba/outbound/2020-07-01/fulfillmentOrders/{sellerFulfillmentOrderId}/status';
        $formParams = [];
        $queryParams = [];
        $headerParams = [];
        $httpBody = '';
        $multipart = false;

        // path params
        if (null !== $seller_fulfillment_order_id) {
            $resourcePath = str_replace(
                '{sellerFulfillmentOrderId}',
                ObjectSerializer::toPathValue($seller_fulfillment_order_id),
                $resourcePath
            );
        }

        $headers = $this->headerSelector->selectHeaders(
            ['application/json'],
            'application/json',
            $multipart
        );

        // for model (json/xml)
        if (isset($body)) {
            if ('application/json' === $headers['Content-Type']) {
                $httpBody = \GuzzleHttp\json_encode(ObjectSerializer::sanitizeForSerialization($body));
            } else {
                $httpBody = $body;
            }
        } elseif (count($formParams) > 0) {
            if ($multipart) {
                $multipartContents = [];
                foreach ($formParams as $formParamName => $formParamValue) {
                    $formParamValueItems = is_array($formParamValue) ? $formParamValue : [$formParamValue];
                    foreach ($formParamValueItems as $formParamValueItem) {
                        $multipartContents[] = [
                            'name' => $formParamName,
                            'contents' => $formParamValueItem,
                        ];
                    }
                }
                // for HTTP post (form)
                $httpBody = new MultipartStream($multipartContents);
            } elseif ('application/json' === $headers['Content-Type']) {
                $httpBody = \GuzzleHttp\json_encode($formParams);
            } else {
                // for HTTP post (form)
                $httpBody = ObjectSerializer::buildQuery($formParams, $this->config);
            }
        }

        $defaultHeaders = [];
        if ($this->config->getUserAgent()) {
            $defaultHeaders['User-Agent'] = $this->config->getUserAgent();
        }

        $headers = array_merge(
            $defaultHeaders,
            $headerParams,
            $headers
        );

        $query = ObjectSerializer::buildQuery($queryParams, $this->config);

        return new Request(
            'PUT',
            $this->config->getHost().$resourcePath.($query ? "?{$query}" : ''),
            $headers,
            $httpBody
        );
    }

    /**
     * Operation updateFulfillmentOrder.
     *
     * @param string                        $seller_fulfillment_order_id
     *                                                                   The identifier assigned to the item by the seller when the fulfillment order was created. (required)
     * @param UpdateFulfillmentOrderRequest $body
     *                                                                   UpdateFulfillmentOrderRequest parameter (required)
     * @param null|string                   $restrictedDataToken         Restricted Data Token (RDT) for accessing restricted resources (optional, required for operations that return PII)
     *
     * @throws ApiException              on non-2xx response
     * @throws \InvalidArgumentException
     */
    public function updateFulfillmentOrder(
        string $seller_fulfillment_order_id,
        UpdateFulfillmentOrderRequest $body,
        ?string $restrictedDataToken = null
    ): UpdateFulfillmentOrderResponse {
        list($response) = $this->updateFulfillmentOrderWithHttpInfo($seller_fulfillment_order_id, $body, $restrictedDataToken);

        return $response;
    }

    /**
     * Operation updateFulfillmentOrderWithHttpInfo.
     *
     * @param string                        $seller_fulfillment_order_id
     *                                                                   The identifier assigned to the item by the seller when the fulfillment order was created. (required)
     * @param UpdateFulfillmentOrderRequest $body
     *                                                                   UpdateFulfillmentOrderRequest parameter (required)
     * @param null|string                   $restrictedDataToken         Restricted Data Token (RDT) for accessing restricted resources (optional, required for operations that return PII)
     *
     * @return array of \SpApi\Model\fulfillment\outbound\v2020_07_01\UpdateFulfillmentOrderResponse, HTTP status code, HTTP response headers (array of strings)
     *
     * @throws ApiException              on non-2xx response
     * @throws \InvalidArgumentException
     */
    public function updateFulfillmentOrderWithHttpInfo(
        string $seller_fulfillment_order_id,
        UpdateFulfillmentOrderRequest $body,
        ?string $restrictedDataToken = null
    ): array {
        $request = $this->updateFulfillmentOrderRequest($seller_fulfillment_order_id, $body);
        if (null !== $restrictedDataToken) {
            $request = RestrictedDataTokenSigner::sign($request, $restrictedDataToken, 'FbaOutboundApi-updateFulfillmentOrder');
        } else {
            $request = $this->config->sign($request);
        }

        try {
            $options = $this->createHttpClientOption();

            try {
                if ($this->rateLimiterEnabled) {
                    $this->updateFulfillmentOrderRateLimiter->consume()->ensureAccepted();
                }
                $response = $this->client->send($request, $options);
            } catch (RequestException $e) {
                throw new ApiException(
                    "[{$e->getCode()}] {$e->getResponse()->getBody()}",
                    (int) $e->getCode(),
                    $e->getResponse() ? $e->getResponse()->getHeaders() : null,
                    $e->getResponse() ? (string) $e->getResponse()->getBody() : null
                );
            } catch (ConnectException $e) {
                throw new ApiException(
                    "[{$e->getCode()}] {$e->getMessage()}",
                    (int) $e->getCode(),
                    null,
                    null
                );
            }

            $statusCode = $response->getStatusCode();

            if ($statusCode < 200 || $statusCode > 299) {
                throw new ApiException(
                    sprintf(
                        '[%d] Error connecting to the API (%s)',
                        $statusCode,
                        (string) $request->getUri()
                    ),
                    $statusCode,
                    $response->getHeaders(),
                    (string) $response->getBody()
                );
            }
            if ('\SpApi\Model\fulfillment\outbound\v2020_07_01\UpdateFulfillmentOrderResponse' === '\SplFileObject') {
                $content = $response->getBody(); // stream goes to serializer
            } else {
                $content = (string) $response->getBody();
                if ('\SpApi\Model\fulfillment\outbound\v2020_07_01\UpdateFulfillmentOrderResponse' !== 'string') {
                    $content = json_decode($content);
                }
            }

            return [
                ObjectSerializer::deserialize($content, '\SpApi\Model\fulfillment\outbound\v2020_07_01\UpdateFulfillmentOrderResponse', []),
                $response->getStatusCode(),
                $response->getHeaders(),
            ];
        } catch (ApiException $e) {
            $data = ObjectSerializer::deserialize(
                $e->getResponseBody(),
                '\SpApi\Model\fulfillment\outbound\v2020_07_01\UpdateFulfillmentOrderResponse',
                $e->getResponseHeaders()
            );
            $e->setResponseObject($data);

            throw $e;
        }
    }

    /**
     * Operation updateFulfillmentOrderAsync.
     *
     * @param string                        $seller_fulfillment_order_id
     *                                                                   The identifier assigned to the item by the seller when the fulfillment order was created. (required)
     * @param UpdateFulfillmentOrderRequest $body
     *                                                                   UpdateFulfillmentOrderRequest parameter (required)
     *
     * @throws \InvalidArgumentException
     */
    public function updateFulfillmentOrderAsync(
        string $seller_fulfillment_order_id,
        UpdateFulfillmentOrderRequest $body
    ): PromiseInterface {
        return $this->updateFulfillmentOrderAsyncWithHttpInfo($seller_fulfillment_order_id, $body)
            ->then(
                function ($response) {
                    return $response[0];
                }
            )
        ;
    }

    /**
     * Operation updateFulfillmentOrderAsyncWithHttpInfo.
     *
     * @param string                        $seller_fulfillment_order_id
     *                                                                   The identifier assigned to the item by the seller when the fulfillment order was created. (required)
     * @param UpdateFulfillmentOrderRequest $body
     *                                                                   UpdateFulfillmentOrderRequest parameter (required)
     *
     * @throws \InvalidArgumentException
     */
    public function updateFulfillmentOrderAsyncWithHttpInfo(
        string $seller_fulfillment_order_id,
        UpdateFulfillmentOrderRequest $body,
        ?string $restrictedDataToken = null
    ): PromiseInterface {
        $returnType = '\SpApi\Model\fulfillment\outbound\v2020_07_01\UpdateFulfillmentOrderResponse';
        $request = $this->updateFulfillmentOrderRequest($seller_fulfillment_order_id, $body);
        if (null !== $restrictedDataToken) {
            $request = RestrictedDataTokenSigner::sign($request, $restrictedDataToken, 'FbaOutboundApi-updateFulfillmentOrder');
        } else {
            $request = $this->config->sign($request);
        }
        if ($this->rateLimiterEnabled) {
            $this->updateFulfillmentOrderRateLimiter->consume()->ensureAccepted();
        }

        return $this->client
            ->sendAsync($request, $this->createHttpClientOption())
            ->then(
                function ($response) use ($returnType) {
                    if ('\SplFileObject' === $returnType) {
                        $content = $response->getBody(); // stream goes to serializer
                    } else {
                        $content = (string) $response->getBody();
                        if ('string' !== $returnType) {
                            $content = json_decode($content);
                        }
                    }

                    return [
                        ObjectSerializer::deserialize($content, $returnType, []),
                        $response->getStatusCode(),
                        $response->getHeaders(),
                    ];
                },
                function ($exception) {
                    $response = $exception->getResponse();
                    $statusCode = $response->getStatusCode();

                    throw new ApiException(
                        sprintf(
                            '[%d] Error connecting to the API (%s)',
                            $statusCode,
                            $exception->getRequest()->getUri()
                        ),
                        $statusCode,
                        $response->getHeaders(),
                        (string) $response->getBody()
                    );
                }
            )
        ;
    }

    /**
     * Create request for operation 'updateFulfillmentOrder'.
     *
     * @param string                        $seller_fulfillment_order_id
     *                                                                   The identifier assigned to the item by the seller when the fulfillment order was created. (required)
     * @param UpdateFulfillmentOrderRequest $body
     *                                                                   UpdateFulfillmentOrderRequest parameter (required)
     *
     * @throws \InvalidArgumentException
     */
    public function updateFulfillmentOrderRequest(
        string $seller_fulfillment_order_id,
        UpdateFulfillmentOrderRequest $body
    ): Request {
        // verify the required parameter 'seller_fulfillment_order_id' is set
        if (null === $seller_fulfillment_order_id || (is_array($seller_fulfillment_order_id) && 0 === count($seller_fulfillment_order_id))) {
            throw new \InvalidArgumentException(
                'Missing the required parameter $seller_fulfillment_order_id when calling updateFulfillmentOrder'
            );
        }
        if (strlen($seller_fulfillment_order_id) > 40) {
            throw new \InvalidArgumentException('invalid length for "$seller_fulfillment_order_id" when calling FbaOutboundApi.updateFulfillmentOrder, must be smaller than or equal to 40.');
        }

        // verify the required parameter 'body' is set
        if (null === $body || (is_array($body) && 0 === count($body))) {
            throw new \InvalidArgumentException(
                'Missing the required parameter $body when calling updateFulfillmentOrder'
            );
        }

        $resourcePath = '/fba/outbound/2020-07-01/fulfillmentOrders/{sellerFulfillmentOrderId}';
        $formParams = [];
        $queryParams = [];
        $headerParams = [];
        $httpBody = '';
        $multipart = false;

        // path params
        if (null !== $seller_fulfillment_order_id) {
            $resourcePath = str_replace(
                '{sellerFulfillmentOrderId}',
                ObjectSerializer::toPathValue($seller_fulfillment_order_id),
                $resourcePath
            );
        }

        $headers = $this->headerSelector->selectHeaders(
            ['application/json'],
            'application/json',
            $multipart
        );

        // for model (json/xml)
        if (isset($body)) {
            if ('application/json' === $headers['Content-Type']) {
                $httpBody = \GuzzleHttp\json_encode(ObjectSerializer::sanitizeForSerialization($body));
            } else {
                $httpBody = $body;
            }
        } elseif (count($formParams) > 0) {
            if ($multipart) {
                $multipartContents = [];
                foreach ($formParams as $formParamName => $formParamValue) {
                    $formParamValueItems = is_array($formParamValue) ? $formParamValue : [$formParamValue];
                    foreach ($formParamValueItems as $formParamValueItem) {
                        $multipartContents[] = [
                            'name' => $formParamName,
                            'contents' => $formParamValueItem,
                        ];
                    }
                }
                // for HTTP post (form)
                $httpBody = new MultipartStream($multipartContents);
            } elseif ('application/json' === $headers['Content-Type']) {
                $httpBody = \GuzzleHttp\json_encode($formParams);
            } else {
                // for HTTP post (form)
                $httpBody = ObjectSerializer::buildQuery($formParams, $this->config);
            }
        }

        $defaultHeaders = [];
        if ($this->config->getUserAgent()) {
            $defaultHeaders['User-Agent'] = $this->config->getUserAgent();
        }

        $headers = array_merge(
            $defaultHeaders,
            $headerParams,
            $headers
        );

        $query = ObjectSerializer::buildQuery($queryParams, $this->config);

        return new Request(
            'PUT',
            $this->config->getHost().$resourcePath.($query ? "?{$query}" : ''),
            $headers,
            $httpBody
        );
    }

    /**
     * Create http client option.
     *
     * @return array of http client options
     *
     * @throws \RuntimeException on file opening failure
     */
    protected function createHttpClientOption(): array
    {
        $options = [];
        if ($this->config->getDebug()) {
            $options[RequestOptions::DEBUG] = fopen($this->config->getDebugFile(), 'a');
            if (!$options[RequestOptions::DEBUG]) {
                throw new \RuntimeException('Failed to open the debug file: '.$this->config->getDebugFile());
            }
        }

        return $options;
    }
}
